summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/Makefile7
-rw-r--r--drivers/acpi/acpi_cmos_rtc.c2
-rw-r--r--drivers/acpi/acpi_extlog.c16
-rw-r--r--drivers/acpi/acpi_lpss.c306
-rw-r--r--drivers/acpi/acpi_memhotplug.c31
-rw-r--r--drivers/acpi/acpi_pad.c16
-rw-r--r--drivers/acpi/acpi_platform.c51
-rw-r--r--drivers/acpi/acpi_pnp.c395
-rw-r--r--drivers/acpi/acpi_processor.c2
-rw-r--r--drivers/acpi/acpica/Makefile1
-rw-r--r--drivers/acpi/acpica/acapps.h170
-rw-r--r--drivers/acpi/acpica/acevents.h5
-rw-r--r--drivers/acpi/acpica/acglobal.h142
-rw-r--r--drivers/acpi/acpica/aclocal.h17
-rw-r--r--drivers/acpi/acpica/acpredef.h10
-rw-r--r--drivers/acpi/acpica/actables.h62
-rw-r--r--drivers/acpi/acpica/acutils.h10
-rw-r--r--drivers/acpi/acpica/evgpe.c13
-rw-r--r--drivers/acpi/acpica/evgpeblk.c34
-rw-r--r--drivers/acpi/acpica/evgpeinit.c12
-rw-r--r--drivers/acpi/acpica/evmisc.c3
-rw-r--r--drivers/acpi/acpica/evsci.c2
-rw-r--r--drivers/acpi/acpica/evxface.c61
-rw-r--r--drivers/acpi/acpica/evxfgpe.c7
-rw-r--r--drivers/acpi/acpica/exconfig.c82
-rw-r--r--drivers/acpi/acpica/exdump.c4
-rw-r--r--drivers/acpi/acpica/hwpci.c15
-rw-r--r--drivers/acpi/acpica/rscreate.c13
-rw-r--r--drivers/acpi/acpica/tbdata.c760
-rw-r--r--drivers/acpi/acpica/tbfadt.c61
-rw-r--r--drivers/acpi/acpica/tbfind.c4
-rw-r--r--drivers/acpi/acpica/tbinstal.c837
-rw-r--r--drivers/acpi/acpica/tbutils.c285
-rw-r--r--drivers/acpi/acpica/tbxface.c18
-rw-r--r--drivers/acpi/acpica/tbxfload.c87
-rw-r--r--drivers/acpi/acpica/utdecode.c74
-rw-r--r--drivers/acpi/acpica/utglobal.c26
-rw-r--r--drivers/acpi/acpica/utstring.c2
-rw-r--r--drivers/acpi/acpica/utxferror.c2
-rw-r--r--drivers/acpi/apei/einj.c14
-rw-r--r--drivers/acpi/battery.c77
-rw-r--r--drivers/acpi/bus.c56
-rw-r--r--drivers/acpi/container.c15
-rw-r--r--drivers/acpi/device_pm.c46
-rw-r--r--drivers/acpi/internal.h18
-rw-r--r--drivers/acpi/nvs.c4
-rw-r--r--drivers/acpi/osl.c32
-rw-r--r--drivers/acpi/processor_driver.c7
-rw-r--r--drivers/acpi/scan.c76
-rw-r--r--drivers/acpi/sleep.c19
-rw-r--r--drivers/acpi/tables.c23
-rw-r--r--drivers/acpi/thermal.c11
-rw-r--r--drivers/acpi/utils.c64
-rw-r--r--drivers/acpi/video.c252
-rw-r--r--drivers/base/dma-buf.c2
-rw-r--r--drivers/base/platform.c7
-rw-r--r--drivers/base/power/main.c66
-rw-r--r--drivers/base/power/opp.c122
-rw-r--r--drivers/base/power/wakeup.c6
-rw-r--r--drivers/char/tpm/tpm_acpi.c4
-rw-r--r--drivers/clk/Makefile1
-rw-r--r--drivers/clk/clk-fractional-divider.c135
-rw-r--r--drivers/clk/rockchip/clk-rockchip.c3
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c5
-rw-r--r--drivers/clk/ti/gate.c2
-rw-r--r--drivers/clocksource/clksrc-of.c2
-rw-r--r--drivers/clocksource/versatile.c6
-rw-r--r--drivers/cpufreq/Kconfig.arm7
-rw-r--r--drivers/cpufreq/Kconfig.x864
-rw-r--r--drivers/cpufreq/Makefile2
-rw-r--r--drivers/cpufreq/acpi-cpufreq.c9
-rw-r--r--drivers/cpufreq/arm_big_little.c16
-rw-r--r--drivers/cpufreq/cpufreq-nforce2.c2
-rw-r--r--drivers/cpufreq/cpufreq.c70
-rw-r--r--drivers/cpufreq/cpufreq_opp.c110
-rw-r--r--drivers/cpufreq/cpufreq_stats.c24
-rw-r--r--drivers/cpufreq/dbx500-cpufreq.c8
-rw-r--r--drivers/cpufreq/elanfreq.c9
-rw-r--r--drivers/cpufreq/exynos-cpufreq.c32
-rw-r--r--drivers/cpufreq/exynos-cpufreq.h1
-rw-r--r--drivers/cpufreq/exynos5440-cpufreq.c30
-rw-r--r--drivers/cpufreq/freq_table.c64
-rw-r--r--drivers/cpufreq/imx6q-cpufreq.c54
-rw-r--r--drivers/cpufreq/intel_pstate.c67
-rw-r--r--drivers/cpufreq/longhaul.c11
-rw-r--r--drivers/cpufreq/pasemi-cpufreq.c10
-rw-r--r--drivers/cpufreq/powernow-k6.c14
-rw-r--r--drivers/cpufreq/powernow-k8.c180
-rw-r--r--drivers/cpufreq/powernow-k8.h2
-rw-r--r--drivers/cpufreq/powernv-cpufreq.c2
-rw-r--r--drivers/cpufreq/ppc_cbe_cpufreq.c9
-rw-r--r--drivers/cpufreq/s3c2416-cpufreq.c40
-rw-r--r--drivers/cpufreq/s3c64xx-cpufreq.c15
-rw-r--r--drivers/cpufreq/s5pv210-cpufreq.c6
-rw-r--r--drivers/cpufreq/speedstep-centrino.c2
-rw-r--r--drivers/cpufreq/tegra-cpufreq.c9
-rw-r--r--drivers/cpuidle/Kconfig.arm6
-rw-r--r--drivers/cpuidle/Makefile1
-rw-r--r--drivers/cpuidle/cpuidle-clps711x.c64
-rw-r--r--drivers/devfreq/Kconfig5
-rw-r--r--drivers/devfreq/devfreq.c125
-rw-r--r--drivers/devfreq/exynos/Makefile2
-rw-r--r--drivers/devfreq/exynos/exynos4_bus.c219
-rw-r--r--drivers/devfreq/exynos/exynos5_bus.c130
-rw-r--r--drivers/devfreq/exynos/exynos_ppmu.c60
-rw-r--r--drivers/devfreq/exynos/exynos_ppmu.h8
-rw-r--r--drivers/firewire/Kconfig2
-rw-r--r--drivers/firewire/core.h1
-rw-r--r--drivers/firewire/net.c4
-rw-r--r--drivers/firewire/ohci.c7
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_ipp.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_backlight.c9
-rw-r--r--drivers/hid/Kconfig13
-rw-r--r--drivers/hid/Makefile1
-rw-r--r--drivers/hid/hid-core.c24
-rw-r--r--drivers/hid/hid-debug.c91
-rw-r--r--drivers/hid/hid-ids.h9
-rw-r--r--drivers/hid/hid-input.c19
-rw-r--r--drivers/hid/hid-rmi.c920
-rw-r--r--drivers/hid/hid-saitek.c154
-rw-r--r--drivers/hid/hid-sensor-hub.c11
-rw-r--r--drivers/hid/hid-sony.c434
-rw-r--r--drivers/hid/hid-thingm.c361
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c45
-rw-r--r--drivers/hid/uhid.c5
-rw-r--r--drivers/hid/usbhid/hid-quirks.c1
-rw-r--r--drivers/irqchip/irq-mxs.c4
-rw-r--r--drivers/irqchip/irq-s3c24xx.c6
-rw-r--r--drivers/irqchip/irqchip.c6
-rw-r--r--drivers/irqchip/irqchip.h7
-rw-r--r--drivers/leds/Kconfig2
-rw-r--r--drivers/media/dvb-core/dvb-usb-ids.h3
-rw-r--r--drivers/media/dvb-frontends/Kconfig7
-rw-r--r--drivers/media/dvb-frontends/Makefile1
-rw-r--r--drivers/media/dvb-frontends/si2168.c760
-rw-r--r--drivers/media/dvb-frontends/si2168.h39
-rw-r--r--drivers/media/dvb-frontends/si2168_priv.h46
-rw-r--r--drivers/media/i2c/ad9389b.c64
-rw-r--r--drivers/media/i2c/adv7180.c2
-rw-r--r--drivers/media/i2c/adv7183.c4
-rw-r--r--drivers/media/i2c/adv7511.c66
-rw-r--r--drivers/media/i2c/adv7604.c4
-rw-r--r--drivers/media/i2c/adv7842.c28
-rw-r--r--drivers/media/i2c/bt819.c2
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.c4
-rw-r--r--drivers/media/i2c/ks0127.c6
-rw-r--r--drivers/media/i2c/m5mols/m5mols_capture.c2
-rw-r--r--drivers/media/i2c/ml86v7667.c2
-rw-r--r--drivers/media/i2c/msp3400-driver.c2
-rw-r--r--drivers/media/i2c/mt9p031.c53
-rw-r--r--drivers/media/i2c/saa6752hs.c2
-rw-r--r--drivers/media/i2c/saa7110.c2
-rw-r--r--drivers/media/i2c/saa7115.c2
-rw-r--r--drivers/media/i2c/saa717x.c2
-rw-r--r--drivers/media/i2c/saa7191.c2
-rw-r--r--drivers/media/i2c/smiapp-pll.h2
-rw-r--r--drivers/media/i2c/smiapp/smiapp-core.c57
-rw-r--r--drivers/media/i2c/smiapp/smiapp-quirk.c55
-rw-r--r--drivers/media/i2c/smiapp/smiapp-quirk.h24
-rw-r--r--drivers/media/i2c/smiapp/smiapp-reg-defs.h8
-rw-r--r--drivers/media/i2c/smiapp/smiapp-regs.c89
-rw-r--r--drivers/media/i2c/smiapp/smiapp-regs.h19
-rw-r--r--drivers/media/i2c/soc_camera/tw9910.c11
-rw-r--r--drivers/media/i2c/sony-btf-mpx.c10
-rw-r--r--drivers/media/i2c/ths8200.c10
-rw-r--r--drivers/media/i2c/tvaudio.c6
-rw-r--r--drivers/media/i2c/tvp514x.c2
-rw-r--r--drivers/media/i2c/tvp5150.c6
-rw-r--r--drivers/media/i2c/tvp7002.c5
-rw-r--r--drivers/media/i2c/tw2804.c2
-rw-r--r--drivers/media/i2c/tw9903.c2
-rw-r--r--drivers/media/i2c/tw9906.c2
-rw-r--r--drivers/media/i2c/vp27smpx.c6
-rw-r--r--drivers/media/i2c/vpx3220.c2
-rw-r--r--drivers/media/media-device.c7
-rw-r--r--drivers/media/media-devnode.c5
-rw-r--r--drivers/media/parport/bw-qcam.c2
-rw-r--r--drivers/media/pci/bt8xx/bttv-cards.c110
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c2
-rw-r--r--drivers/media/pci/bt8xx/bttv.h1
-rw-r--r--drivers/media/pci/bt8xx/dst.c20
-rw-r--r--drivers/media/pci/cx18/cx18-av-core.c2
-rw-r--r--drivers/media/pci/cx18/cx18-fileops.c2
-rw-r--r--drivers/media/pci/cx18/cx18-gpio.c6
-rw-r--r--drivers/media/pci/cx18/cx18-ioctl.c2
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c4
-rw-r--r--drivers/media/pci/cx88/cx88-core.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-alsa-pcm.c6
-rw-r--r--drivers/media/pci/ivtv/ivtv-fileops.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-ioctl.c2
-rw-r--r--drivers/media/pci/saa7134/Kconfig4
-rw-r--r--drivers/media/pci/saa7134/saa7134-alsa.c107
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c130
-rw-r--r--drivers/media/pci/saa7134/saa7134-dvb.c50
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c187
-rw-r--r--drivers/media/pci/saa7134/saa7134-i2c.c7
-rw-r--r--drivers/media/pci/saa7134/saa7134-reg.h12
-rw-r--r--drivers/media/pci/saa7134/saa7134-ts.c191
-rw-r--r--drivers/media/pci/saa7134/saa7134-tvaudio.c7
-rw-r--r--drivers/media/pci/saa7134/saa7134-vbi.c175
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c697
-rw-r--r--drivers/media/pci/saa7134/saa7134.h108
-rw-r--r--drivers/media/pci/saa7146/mxb.c14
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.c7
-rw-r--r--drivers/media/pci/ttpci/av7110_av.c6
-rw-r--r--drivers/media/pci/zoran/zoran_device.c2
-rw-r--r--drivers/media/pci/zoran/zoran_driver.c2
-rw-r--r--drivers/media/platform/blackfin/bfin_capture.c14
-rw-r--r--drivers/media/platform/coda.c6
-rw-r--r--drivers/media/platform/davinci/vpbe_display.c55
-rw-r--r--drivers/media/platform/davinci/vpfe_capture.c15
-rw-r--r--drivers/media/platform/davinci/vpif_capture.c1119
-rw-r--r--drivers/media/platform/davinci/vpif_capture.h28
-rw-r--r--drivers/media/platform/davinci/vpif_display.c1206
-rw-r--r--drivers/media/platform/davinci/vpif_display.h44
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-m2m.c4
-rw-r--r--drivers/media/platform/exynos4-is/Kconfig3
-rw-r--r--drivers/media/platform/exynos4-is/common.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c6
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.c6
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.h2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is.c3
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp-video.c7
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp.h2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite-reg.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.c8
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.h2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-m2m.c9
-rw-r--r--drivers/media/platform/exynos4-is/fimc-reg.c2
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c329
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.h2
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c43
-rw-r--r--drivers/media/platform/fsl-viu.c2
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c7
-rw-r--r--drivers/media/platform/mem2mem_testdev.c5
-rw-r--r--drivers/media/platform/mx2_emmaprp.c37
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c4
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.c122
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.h6
-rw-r--r--drivers/media/platform/s5p-mfc/regs-mfc-v6.h4
-rw-r--r--drivers/media/platform/s5p-mfc/regs-mfc-v7.h5
-rw-r--r--drivers/media/platform/s5p-mfc/regs-mfc-v8.h124
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c79
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_common.h15
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c62
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h3
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c290
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c96
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr.c6
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr.h254
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c842
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h7
-rw-r--r--drivers/media/platform/s5p-tv/hdmi_drv.c14
-rw-r--r--drivers/media/platform/s5p-tv/hdmiphy_drv.c9
-rw-r--r--drivers/media/platform/s5p-tv/mixer_video.c11
-rw-r--r--drivers/media/platform/soc_camera/atmel-isi.c6
-rw-r--r--drivers/media/platform/soc_camera/mx2_camera.c4
-rw-r--r--drivers/media/platform/soc_camera/mx3_camera.c4
-rw-r--r--drivers/media/platform/soc_camera/rcar_vin.c4
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c4
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c12
-rw-r--r--drivers/media/platform/ti-vpe/csc.c6
-rw-r--r--drivers/media/platform/ti-vpe/sc.c4
-rw-r--r--drivers/media/platform/ti-vpe/vpdma.c68
-rw-r--r--drivers/media/platform/ti-vpe/vpdma.h17
-rw-r--r--drivers/media/platform/ti-vpe/vpe.c227
-rw-r--r--drivers/media/platform/timblogiw.c10
-rw-r--r--drivers/media/platform/vino.c6
-rw-r--r--drivers/media/platform/vivi.c3
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.c4
-rw-r--r--drivers/media/rc/mceusb.c65
-rw-r--r--drivers/media/tuners/Kconfig7
-rw-r--r--drivers/media/tuners/Makefile1
-rw-r--r--drivers/media/tuners/si2157.c260
-rw-r--r--drivers/media/tuners/si2157.h34
-rw-r--r--drivers/media/tuners/si2157_priv.h37
-rw-r--r--drivers/media/tuners/xc5000.c302
-rw-r--r--drivers/media/usb/au0828/au0828-dvb.c57
-rw-r--r--drivers/media/usb/au0828/au0828-video.c4
-rw-r--r--drivers/media/usb/au0828/au0828.h2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c6
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c6
-rw-r--r--drivers/media/usb/dvb-usb/az6027.c7
-rw-r--r--drivers/media/usb/dvb-usb/dib0700.h2
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_core.c43
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_devices.c2
-rw-r--r--drivers/media/usb/dvb-usb/technisat-usb2.c28
-rw-r--r--drivers/media/usb/em28xx/Kconfig2
-rw-r--r--drivers/media/usb/em28xx/em28xx-audio.c39
-rw-r--r--drivers/media/usb/em28xx/em28xx-camera.c51
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c47
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c89
-rw-r--r--drivers/media/usb/em28xx/em28xx-i2c.c1
-rw-r--r--drivers/media/usb/em28xx/em28xx-v4l.h2
-rw-r--r--drivers/media/usb/em28xx/em28xx-vbi.c10
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c622
-rw-r--r--drivers/media/usb/em28xx/em28xx.h153
-rw-r--r--drivers/media/usb/gspca/Kconfig10
-rw-r--r--drivers/media/usb/gspca/Makefile2
-rw-r--r--drivers/media/usb/gspca/dtcs033.c441
-rw-r--r--drivers/media/usb/gspca/gl860/gl860-mi2020.c464
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.c2
-rw-r--r--drivers/media/usb/pwc/pwc-if.c7
-rw-r--r--drivers/media/usb/s2255/s2255drv.c11
-rw-r--r--drivers/media/usb/stk1160/stk1160-core.c10
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c8
-rw-r--r--drivers/media/usb/stk1160/stk1160.h1
-rw-r--r--drivers/media/usb/tm6000/tm6000-cards.c2
-rw-r--r--drivers/media/usb/tm6000/tm6000-video.c2
-rw-r--r--drivers/media/usb/usbtv/usbtv-video.c9
-rw-r--r--drivers/media/usb/usbvision/usbvision-video.c2
-rw-r--r--drivers/media/usb/uvc/uvc_video.c36
-rw-r--r--drivers/media/v4l2-core/Kconfig4
-rw-r--r--drivers/media/v4l2-core/Makefile1
-rw-r--r--drivers/media/v4l2-core/tuner-core.c6
-rw-r--r--drivers/media/v4l2-core/v4l2-device.c18
-rw-r--r--drivers/media/v4l2-core/v4l2-dv-timings.c11
-rw-r--r--drivers/media/v4l2-core/v4l2-event.c36
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c12
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c67
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-contig.c2
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c706
-rw-r--r--drivers/media/v4l2-core/videobuf2-dma-sg.c2
-rw-r--r--drivers/media/v4l2-core/videobuf2-dvb.c336
-rw-r--r--drivers/mfd/db8500-prcmu.c19
-rw-r--r--drivers/mfd/mc13xxx-core.c10
-rw-r--r--drivers/net/irda/sh_sir.c14
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h4
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.h2
-rw-r--r--drivers/of/Kconfig1
-rw-r--r--drivers/of/Makefile4
-rw-r--r--drivers/of/address.c22
-rw-r--r--drivers/of/base.c123
-rw-r--r--drivers/of/fdt.c458
-rw-r--r--drivers/of/fdt_address.c241
-rw-r--r--drivers/of/irq.c22
-rw-r--r--drivers/of/of_pci_irq.c8
-rw-r--r--drivers/of/of_reserved_mem.c6
-rw-r--r--drivers/of/platform.c76
-rw-r--r--drivers/of/selftest.c80
-rw-r--r--drivers/of/testcase-data/testcases.dtsi1
-rw-r--r--drivers/of/testcase-data/tests-phandle.dtsi6
-rw-r--r--drivers/of/testcase-data/tests-platform.dtsi35
-rw-r--r--drivers/pci/pci.c6
-rw-r--r--drivers/platform/x86/acer-wmi.c10
-rw-r--r--drivers/pnp/pnpacpi/core.c28
-rw-r--r--drivers/pnp/resource.c4
-rw-r--r--drivers/power/power_supply_core.c15
-rw-r--r--drivers/powercap/intel_rapl.c33
-rw-r--r--drivers/s390/char/sclp_early.c34
-rw-r--r--drivers/scsi/aic7xxx/aic79xx.h2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c10
-rw-r--r--drivers/sh/clk/core.c20
-rw-r--r--drivers/staging/lustre/lustre/llite/file.c17
-rw-r--r--drivers/staging/media/as102/as102_usb_drv.c7
-rw-r--r--drivers/staging/media/bcm2048/radio-bcm2048.c2
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h2
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.c27
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.h2
-rw-r--r--drivers/staging/media/dt3155v4l/dt3155v4l.c7
-rw-r--r--drivers/staging/media/go7007/go7007-v4l2.c5
-rw-r--r--drivers/staging/media/go7007/go7007.txt1
-rw-r--r--drivers/staging/media/go7007/s2250-board.c2
-rw-r--r--drivers/staging/media/go7007/saa7134-go7007.c4
-rw-r--r--drivers/staging/media/msi3101/sdr-msi3101.c24
-rw-r--r--drivers/staging/media/omap24xx/tcm825x.c12
-rw-r--r--drivers/staging/media/omap24xx/tcm825x.h4
-rw-r--r--drivers/staging/media/omap4iss/Kconfig6
-rw-r--r--drivers/staging/media/omap4iss/iss.c52
-rw-r--r--drivers/staging/media/omap4iss/iss.h14
-rw-r--r--drivers/staging/media/omap4iss/iss_csi2.c39
-rw-r--r--drivers/staging/media/omap4iss/iss_video.h2
-rw-r--r--drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c7
-rw-r--r--drivers/staging/media/sn9c102/sn9c102.h30
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_core.c342
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_devtable.h22
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_hv7131d.c22
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_hv7131r.c23
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_mi0343.c30
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_mi0360.c30
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_ov7630.c22
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_ov7660.c22
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_pas106b.c22
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_pas202bcb.c22
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_sensor.h34
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_tas5110c1b.c18
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_tas5110d.c14
-rw-r--r--drivers/staging/media/sn9c102/sn9c102_tas5130d1b.c18
-rw-r--r--drivers/staging/media/solo6x10/Kconfig12
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-enc.c31
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-offsets.h2
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c3
-rw-r--r--drivers/staging/media/solo6x10/solo6x10-v4l2.c3
-rw-r--r--drivers/thermal/cpu_cooling.c33
-rw-r--r--drivers/tty/serial/amba-pl011.c1
-rw-r--r--drivers/tty/serial/earlycon.c28
-rw-r--r--drivers/video/backlight/backlight.c40
-rw-r--r--drivers/video/console/fbcon.c1
-rw-r--r--drivers/video/fbdev/Kconfig11
-rw-r--r--drivers/video/fbdev/bf54x-lq043fb.c2
-rw-r--r--drivers/video/fbdev/core/fbmem.c7
-rw-r--r--drivers/video/fbdev/core/fbmon.c9
-rw-r--r--drivers/video/fbdev/da8xx-fb.c14
-rw-r--r--drivers/video/fbdev/exynos/Kconfig2
-rw-r--r--drivers/video/fbdev/fb-puv3.c2
-rw-r--r--drivers/video/fbdev/gbefb.c2
-rw-r--r--drivers/video/fbdev/grvga.c3
-rw-r--r--drivers/video/fbdev/matrox/matroxfb_base.h2
-rw-r--r--drivers/video/fbdev/mbx/Makefile3
-rw-r--r--drivers/video/fbdev/mbx/mbxdebugfs.c2
-rw-r--r--drivers/video/fbdev/mbx/mbxfb.c2
-rw-r--r--drivers/video/fbdev/mmp/Kconfig2
-rw-r--r--drivers/video/fbdev/mmp/fb/mmpfb.c9
-rw-r--r--drivers/video/fbdev/mmp/hw/Kconfig6
-rw-r--r--drivers/video/fbdev/mmp/hw/mmp_ctrl.h32
-rw-r--r--drivers/video/fbdev/mx3fb.c85
-rw-r--r--drivers/video/fbdev/omap/Kconfig9
-rw-r--r--drivers/video/fbdev/omap/Makefile23
-rw-r--r--drivers/video/fbdev/omap/lcdc.c67
-rw-r--r--drivers/video/fbdev/omap/omapfb_main.c1
-rw-r--r--drivers/video/fbdev/omap2/Makefile2
-rw-r--r--drivers/video/fbdev/omap2/displays-new/connector-hdmi.c25
-rw-r--r--drivers/video/fbdev/omap2/displays-new/panel-dpi.c95
-rw-r--r--drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c77
-rw-r--r--drivers/video/fbdev/omap2/displays-new/panel-nec-nl8048hl11.c45
-rw-r--r--drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c210
-rw-r--r--drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c33
-rw-r--r--drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c42
-rw-r--r--drivers/video/fbdev/omap2/dss/Kconfig26
-rw-r--r--drivers/video/fbdev/omap2/dss/Makefile7
-rw-r--r--drivers/video/fbdev/omap2/dss/core.c6
-rw-r--r--drivers/video/fbdev/omap2/dss/dispc.c22
-rw-r--r--drivers/video/fbdev/omap2/dss/dpi.c4
-rw-r--r--drivers/video/fbdev/omap2/dss/dsi.c18
-rw-r--r--drivers/video/fbdev/omap2/dss/dss.c20
-rw-r--r--drivers/video/fbdev/omap2/dss/dss.h3
-rw-r--r--drivers/video/fbdev/omap2/dss/dss_features.c70
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi.h17
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi4.c113
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi4_core.c28
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi5.c829
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi5_core.c922
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi5_core.h306
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_common.c41
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_phy.c265
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_pll.c107
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_wp.c29
-rw-r--r--drivers/video/fbdev/omap2/dss/omapdss-boot-init.c229
-rw-r--r--drivers/video/fbdev/omap2/dss/venc_panel.c232
-rw-r--r--drivers/video/fbdev/pxa3xx-gcu.c6
-rw-r--r--drivers/video/fbdev/s3fb.c3
-rw-r--r--drivers/video/fbdev/wm8505fb.c2
-rw-r--r--drivers/video/of_display_timing.c10
454 files changed, 18222 insertions, 9254 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index bce34afadcd0..ea55e0179f81 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -39,8 +39,9 @@ acpi-y += processor_core.o
acpi-y += ec.o
acpi-$(CONFIG_ACPI_DOCK) += dock.o
acpi-y += pci_root.o pci_link.o pci_irq.o
-acpi-$(CONFIG_X86_INTEL_LPSS) += acpi_lpss.o
+acpi-y += acpi_lpss.o
acpi-y += acpi_platform.o
+acpi-y += acpi_pnp.o
acpi-y += power.o
acpi-y += event.o
acpi-y += sysfs.o
@@ -63,9 +64,9 @@ obj-$(CONFIG_ACPI_FAN) += fan.o
obj-$(CONFIG_ACPI_VIDEO) += video.o
obj-$(CONFIG_ACPI_PCI_SLOT) += pci_slot.o
obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
-obj-$(CONFIG_ACPI_CONTAINER) += container.o
+obj-y += container.o
obj-$(CONFIG_ACPI_THERMAL) += thermal.o
-obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
+obj-y += acpi_memhotplug.o
obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_SBS) += sbshc.o
obj-$(CONFIG_ACPI_SBS) += sbs.o
diff --git a/drivers/acpi/acpi_cmos_rtc.c b/drivers/acpi/acpi_cmos_rtc.c
index 961b45d18a5d..2da8660262e5 100644
--- a/drivers/acpi/acpi_cmos_rtc.c
+++ b/drivers/acpi/acpi_cmos_rtc.c
@@ -68,7 +68,7 @@ static int acpi_install_cmos_rtc_space_handler(struct acpi_device *adev,
return -ENODEV;
}
- return 0;
+ return 1;
}
static void acpi_remove_cmos_rtc_space_handler(struct acpi_device *adev)
diff --git a/drivers/acpi/acpi_extlog.c b/drivers/acpi/acpi_extlog.c
index c4a5d87ede7e..185334114d71 100644
--- a/drivers/acpi/acpi_extlog.c
+++ b/drivers/acpi/acpi_extlog.c
@@ -220,13 +220,13 @@ static int __init extlog_init(void)
goto err;
}
- extlog_l1_hdr = acpi_os_map_memory(l1_dirbase, l1_hdr_size);
+ extlog_l1_hdr = acpi_os_map_iomem(l1_dirbase, l1_hdr_size);
l1_head = (struct extlog_l1_head *)extlog_l1_hdr;
l1_size = l1_head->total_len;
l1_percpu_entry = l1_head->entries;
elog_base = l1_head->elog_base;
elog_size = l1_head->elog_len;
- acpi_os_unmap_memory(extlog_l1_hdr, l1_hdr_size);
+ acpi_os_unmap_iomem(extlog_l1_hdr, l1_hdr_size);
release_mem_region(l1_dirbase, l1_hdr_size);
/* remap L1 header again based on completed information */
@@ -237,7 +237,7 @@ static int __init extlog_init(void)
(unsigned long long)l1_dirbase + l1_size);
goto err;
}
- extlog_l1_addr = acpi_os_map_memory(l1_dirbase, l1_size);
+ extlog_l1_addr = acpi_os_map_iomem(l1_dirbase, l1_size);
l1_entry_base = (u64 *)((u8 *)extlog_l1_addr + l1_hdr_size);
/* remap elog table */
@@ -248,7 +248,7 @@ static int __init extlog_init(void)
(unsigned long long)elog_base + elog_size);
goto err_release_l1_dir;
}
- elog_addr = acpi_os_map_memory(elog_base, elog_size);
+ elog_addr = acpi_os_map_iomem(elog_base, elog_size);
rc = -ENOMEM;
/* allocate buffer to save elog record */
@@ -270,11 +270,11 @@ static int __init extlog_init(void)
err_release_elog:
if (elog_addr)
- acpi_os_unmap_memory(elog_addr, elog_size);
+ acpi_os_unmap_iomem(elog_addr, elog_size);
release_mem_region(elog_base, elog_size);
err_release_l1_dir:
if (extlog_l1_addr)
- acpi_os_unmap_memory(extlog_l1_addr, l1_size);
+ acpi_os_unmap_iomem(extlog_l1_addr, l1_size);
release_mem_region(l1_dirbase, l1_size);
err:
pr_warn(FW_BUG "Extended error log disabled because of problems parsing f/w tables\n");
@@ -287,9 +287,9 @@ static void __exit extlog_exit(void)
mce_unregister_decode_chain(&extlog_mce_dec);
((struct extlog_l1_head *)extlog_l1_addr)->flags &= ~FLAG_OS_OPTIN;
if (extlog_l1_addr)
- acpi_os_unmap_memory(extlog_l1_addr, l1_size);
+ acpi_os_unmap_iomem(extlog_l1_addr, l1_size);
if (elog_addr)
- acpi_os_unmap_memory(elog_addr, elog_size);
+ acpi_os_unmap_iomem(elog_addr, elog_size);
release_mem_region(elog_base, elog_size);
release_mem_region(l1_dirbase, l1_size);
kfree(elog_buf);
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index d79c6d7f598e..63407d264885 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -19,15 +19,21 @@
#include <linux/platform_device.h>
#include <linux/platform_data/clk-lpss.h>
#include <linux/pm_runtime.h>
+#include <linux/delay.h>
#include "internal.h"
ACPI_MODULE_NAME("acpi_lpss");
+#ifdef CONFIG_X86_INTEL_LPSS
+
+#define LPSS_ADDR(desc) ((unsigned long)&desc)
+
#define LPSS_CLK_SIZE 0x04
#define LPSS_LTR_SIZE 0x18
/* Offsets relative to LPSS_PRIVATE_OFFSET */
+#define LPSS_CLK_DIVIDER_DEF_MASK (BIT(1) | BIT(16))
#define LPSS_GENERAL 0x08
#define LPSS_GENERAL_LTR_MODE_SW BIT(2)
#define LPSS_GENERAL_UART_RTS_OVRD BIT(3)
@@ -43,6 +49,8 @@ ACPI_MODULE_NAME("acpi_lpss");
#define LPSS_TX_INT 0x20
#define LPSS_TX_INT_MASK BIT(1)
+#define LPSS_PRV_REG_COUNT 9
+
struct lpss_shared_clock {
const char *name;
unsigned long rate;
@@ -57,7 +65,9 @@ struct lpss_device_desc {
bool ltr_required;
unsigned int prv_offset;
size_t prv_size_override;
+ bool clk_divider;
bool clk_gate;
+ bool save_ctx;
struct lpss_shared_clock *shared_clock;
void (*setup)(struct lpss_private_data *pdata);
};
@@ -72,6 +82,7 @@ struct lpss_private_data {
resource_size_t mmio_size;
struct clk *clk;
const struct lpss_device_desc *dev_desc;
+ u32 prv_reg_ctx[LPSS_PRV_REG_COUNT];
};
static void lpss_uart_setup(struct lpss_private_data *pdata)
@@ -92,6 +103,14 @@ static struct lpss_device_desc lpt_dev_desc = {
.clk_required = true,
.prv_offset = 0x800,
.ltr_required = true,
+ .clk_divider = true,
+ .clk_gate = true,
+};
+
+static struct lpss_device_desc lpt_i2c_dev_desc = {
+ .clk_required = true,
+ .prv_offset = 0x800,
+ .ltr_required = true,
.clk_gate = true,
};
@@ -99,6 +118,7 @@ static struct lpss_device_desc lpt_uart_dev_desc = {
.clk_required = true,
.prv_offset = 0x800,
.ltr_required = true,
+ .clk_divider = true,
.clk_gate = true,
.setup = lpss_uart_setup,
};
@@ -116,32 +136,25 @@ static struct lpss_shared_clock pwm_clock = {
static struct lpss_device_desc byt_pwm_dev_desc = {
.clk_required = true,
+ .save_ctx = true,
.shared_clock = &pwm_clock,
};
-static struct lpss_shared_clock uart_clock = {
- .name = "uart_clk",
- .rate = 44236800,
-};
-
static struct lpss_device_desc byt_uart_dev_desc = {
.clk_required = true,
.prv_offset = 0x800,
+ .clk_divider = true,
.clk_gate = true,
- .shared_clock = &uart_clock,
+ .save_ctx = true,
.setup = lpss_uart_setup,
};
-static struct lpss_shared_clock spi_clock = {
- .name = "spi_clk",
- .rate = 50000000,
-};
-
static struct lpss_device_desc byt_spi_dev_desc = {
.clk_required = true,
.prv_offset = 0x400,
+ .clk_divider = true,
.clk_gate = true,
- .shared_clock = &spi_clock,
+ .save_ctx = true,
};
static struct lpss_device_desc byt_sdio_dev_desc = {
@@ -156,44 +169,53 @@ static struct lpss_shared_clock i2c_clock = {
static struct lpss_device_desc byt_i2c_dev_desc = {
.clk_required = true,
.prv_offset = 0x800,
+ .save_ctx = true,
.shared_clock = &i2c_clock,
};
+#else
+
+#define LPSS_ADDR(desc) (0UL)
+
+#endif /* CONFIG_X86_INTEL_LPSS */
+
static const struct acpi_device_id acpi_lpss_device_ids[] = {
/* Generic LPSS devices */
- { "INTL9C60", (unsigned long)&lpss_dma_desc },
+ { "INTL9C60", LPSS_ADDR(lpss_dma_desc) },
/* Lynxpoint LPSS devices */
- { "INT33C0", (unsigned long)&lpt_dev_desc },
- { "INT33C1", (unsigned long)&lpt_dev_desc },
- { "INT33C2", (unsigned long)&lpt_dev_desc },
- { "INT33C3", (unsigned long)&lpt_dev_desc },
- { "INT33C4", (unsigned long)&lpt_uart_dev_desc },
- { "INT33C5", (unsigned long)&lpt_uart_dev_desc },
- { "INT33C6", (unsigned long)&lpt_sdio_dev_desc },
+ { "INT33C0", LPSS_ADDR(lpt_dev_desc) },
+ { "INT33C1", LPSS_ADDR(lpt_dev_desc) },
+ { "INT33C2", LPSS_ADDR(lpt_i2c_dev_desc) },
+ { "INT33C3", LPSS_ADDR(lpt_i2c_dev_desc) },
+ { "INT33C4", LPSS_ADDR(lpt_uart_dev_desc) },
+ { "INT33C5", LPSS_ADDR(lpt_uart_dev_desc) },
+ { "INT33C6", LPSS_ADDR(lpt_sdio_dev_desc) },
{ "INT33C7", },
/* BayTrail LPSS devices */
- { "80860F09", (unsigned long)&byt_pwm_dev_desc },
- { "80860F0A", (unsigned long)&byt_uart_dev_desc },
- { "80860F0E", (unsigned long)&byt_spi_dev_desc },
- { "80860F14", (unsigned long)&byt_sdio_dev_desc },
- { "80860F41", (unsigned long)&byt_i2c_dev_desc },
+ { "80860F09", LPSS_ADDR(byt_pwm_dev_desc) },
+ { "80860F0A", LPSS_ADDR(byt_uart_dev_desc) },
+ { "80860F0E", LPSS_ADDR(byt_spi_dev_desc) },
+ { "80860F14", LPSS_ADDR(byt_sdio_dev_desc) },
+ { "80860F41", LPSS_ADDR(byt_i2c_dev_desc) },
{ "INT33B2", },
{ "INT33FC", },
- { "INT3430", (unsigned long)&lpt_dev_desc },
- { "INT3431", (unsigned long)&lpt_dev_desc },
- { "INT3432", (unsigned long)&lpt_dev_desc },
- { "INT3433", (unsigned long)&lpt_dev_desc },
- { "INT3434", (unsigned long)&lpt_uart_dev_desc },
- { "INT3435", (unsigned long)&lpt_uart_dev_desc },
- { "INT3436", (unsigned long)&lpt_sdio_dev_desc },
+ { "INT3430", LPSS_ADDR(lpt_dev_desc) },
+ { "INT3431", LPSS_ADDR(lpt_dev_desc) },
+ { "INT3432", LPSS_ADDR(lpt_i2c_dev_desc) },
+ { "INT3433", LPSS_ADDR(lpt_i2c_dev_desc) },
+ { "INT3434", LPSS_ADDR(lpt_uart_dev_desc) },
+ { "INT3435", LPSS_ADDR(lpt_uart_dev_desc) },
+ { "INT3436", LPSS_ADDR(lpt_sdio_dev_desc) },
{ "INT3437", },
{ }
};
+#ifdef CONFIG_X86_INTEL_LPSS
+
static int is_memory(struct acpi_resource *res, void *not_used)
{
struct resource r;
@@ -213,9 +235,11 @@ static int register_device_clock(struct acpi_device *adev,
{
const struct lpss_device_desc *dev_desc = pdata->dev_desc;
struct lpss_shared_clock *shared_clock = dev_desc->shared_clock;
+ const char *devname = dev_name(&adev->dev);
struct clk *clk = ERR_PTR(-ENODEV);
struct lpss_clk_data *clk_data;
- const char *parent;
+ const char *parent, *clk_name;
+ void __iomem *prv_base;
if (!lpss_clk_dev)
lpt_register_clock_device();
@@ -226,7 +250,7 @@ static int register_device_clock(struct acpi_device *adev,
if (dev_desc->clkdev_name) {
clk_register_clkdev(clk_data->clk, dev_desc->clkdev_name,
- dev_name(&adev->dev));
+ devname);
return 0;
}
@@ -235,6 +259,7 @@ static int register_device_clock(struct acpi_device *adev,
return -ENODATA;
parent = clk_data->name;
+ prv_base = pdata->mmio_base + dev_desc->prv_offset;
if (shared_clock) {
clk = shared_clock->clk;
@@ -248,16 +273,41 @@ static int register_device_clock(struct acpi_device *adev,
}
if (dev_desc->clk_gate) {
- clk = clk_register_gate(NULL, dev_name(&adev->dev), parent, 0,
- pdata->mmio_base + dev_desc->prv_offset,
- 0, 0, NULL);
- pdata->clk = clk;
+ clk = clk_register_gate(NULL, devname, parent, 0,
+ prv_base, 0, 0, NULL);
+ parent = devname;
+ }
+
+ if (dev_desc->clk_divider) {
+ /* Prevent division by zero */
+ if (!readl(prv_base))
+ writel(LPSS_CLK_DIVIDER_DEF_MASK, prv_base);
+
+ clk_name = kasprintf(GFP_KERNEL, "%s-div", devname);
+ if (!clk_name)
+ return -ENOMEM;
+ clk = clk_register_fractional_divider(NULL, clk_name, parent,
+ 0, prv_base,
+ 1, 15, 16, 15, 0, NULL);
+ parent = clk_name;
+
+ clk_name = kasprintf(GFP_KERNEL, "%s-update", devname);
+ if (!clk_name) {
+ kfree(parent);
+ return -ENOMEM;
+ }
+ clk = clk_register_gate(NULL, clk_name, parent,
+ CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE,
+ prv_base, 31, 0, NULL);
+ kfree(parent);
+ kfree(clk_name);
}
if (IS_ERR(clk))
return PTR_ERR(clk);
- clk_register_clkdev(clk, NULL, dev_name(&adev->dev));
+ pdata->clk = clk;
+ clk_register_clkdev(clk, NULL, devname);
return 0;
}
@@ -268,12 +318,14 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
struct lpss_private_data *pdata;
struct resource_list_entry *rentry;
struct list_head resource_list;
+ struct platform_device *pdev;
int ret;
dev_desc = (struct lpss_device_desc *)id->driver_data;
- if (!dev_desc)
- return acpi_create_platform_device(adev, id);
-
+ if (!dev_desc) {
+ pdev = acpi_create_platform_device(adev);
+ return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1;
+ }
pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
@@ -323,10 +375,13 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
dev_desc->setup(pdata);
adev->driver_data = pdata;
- ret = acpi_create_platform_device(adev, id);
- if (ret > 0)
- return ret;
+ pdev = acpi_create_platform_device(adev);
+ if (!IS_ERR_OR_NULL(pdev)) {
+ device_enable_async_suspend(&pdev->dev);
+ return 1;
+ }
+ ret = PTR_ERR(pdev);
adev->driver_data = NULL;
err_out:
@@ -450,6 +505,126 @@ static void acpi_lpss_set_ltr(struct device *dev, s32 val)
}
}
+#ifdef CONFIG_PM
+/**
+ * acpi_lpss_save_ctx() - Save the private registers of LPSS device
+ * @dev: LPSS device
+ *
+ * Most LPSS devices have private registers which may loose their context when
+ * the device is powered down. acpi_lpss_save_ctx() saves those registers into
+ * prv_reg_ctx array.
+ */
+static void acpi_lpss_save_ctx(struct device *dev)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ unsigned int i;
+
+ for (i = 0; i < LPSS_PRV_REG_COUNT; i++) {
+ unsigned long offset = i * sizeof(u32);
+
+ pdata->prv_reg_ctx[i] = __lpss_reg_read(pdata, offset);
+ dev_dbg(dev, "saving 0x%08x from LPSS reg at offset 0x%02lx\n",
+ pdata->prv_reg_ctx[i], offset);
+ }
+}
+
+/**
+ * acpi_lpss_restore_ctx() - Restore the private registers of LPSS device
+ * @dev: LPSS device
+ *
+ * Restores the registers that were previously stored with acpi_lpss_save_ctx().
+ */
+static void acpi_lpss_restore_ctx(struct device *dev)
+{
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ unsigned int i;
+
+ /*
+ * The following delay is needed or the subsequent write operations may
+ * fail. The LPSS devices are actually PCI devices and the PCI spec
+ * expects 10ms delay before the device can be accessed after D3 to D0
+ * transition.
+ */
+ msleep(10);
+
+ for (i = 0; i < LPSS_PRV_REG_COUNT; i++) {
+ unsigned long offset = i * sizeof(u32);
+
+ __lpss_reg_write(pdata->prv_reg_ctx[i], pdata, offset);
+ dev_dbg(dev, "restoring 0x%08x to LPSS reg at offset 0x%02lx\n",
+ pdata->prv_reg_ctx[i], offset);
+ }
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int acpi_lpss_suspend_late(struct device *dev)
+{
+ int ret = pm_generic_suspend_late(dev);
+
+ if (ret)
+ return ret;
+
+ acpi_lpss_save_ctx(dev);
+ return acpi_dev_suspend_late(dev);
+}
+
+static int acpi_lpss_restore_early(struct device *dev)
+{
+ int ret = acpi_dev_resume_early(dev);
+
+ if (ret)
+ return ret;
+
+ acpi_lpss_restore_ctx(dev);
+ return pm_generic_resume_early(dev);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM_RUNTIME
+static int acpi_lpss_runtime_suspend(struct device *dev)
+{
+ int ret = pm_generic_runtime_suspend(dev);
+
+ if (ret)
+ return ret;
+
+ acpi_lpss_save_ctx(dev);
+ return acpi_dev_runtime_suspend(dev);
+}
+
+static int acpi_lpss_runtime_resume(struct device *dev)
+{
+ int ret = acpi_dev_runtime_resume(dev);
+
+ if (ret)
+ return ret;
+
+ acpi_lpss_restore_ctx(dev);
+ return pm_generic_runtime_resume(dev);
+}
+#endif /* CONFIG_PM_RUNTIME */
+#endif /* CONFIG_PM */
+
+static struct dev_pm_domain acpi_lpss_pm_domain = {
+ .ops = {
+#ifdef CONFIG_PM_SLEEP
+ .suspend_late = acpi_lpss_suspend_late,
+ .restore_early = acpi_lpss_restore_early,
+ .prepare = acpi_subsys_prepare,
+ .complete = acpi_subsys_complete,
+ .suspend = acpi_subsys_suspend,
+ .resume_early = acpi_subsys_resume_early,
+ .freeze = acpi_subsys_freeze,
+ .poweroff = acpi_subsys_suspend,
+ .poweroff_late = acpi_subsys_suspend_late,
+#endif
+#ifdef CONFIG_PM_RUNTIME
+ .runtime_suspend = acpi_lpss_runtime_suspend,
+ .runtime_resume = acpi_lpss_runtime_resume,
+#endif
+ },
+};
+
static int acpi_lpss_platform_notify(struct notifier_block *nb,
unsigned long action, void *data)
{
@@ -457,7 +632,6 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
struct lpss_private_data *pdata;
struct acpi_device *adev;
const struct acpi_device_id *id;
- int ret = 0;
id = acpi_match_device(acpi_lpss_device_ids, &pdev->dev);
if (!id || !id->driver_data)
@@ -467,7 +641,7 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
return 0;
pdata = acpi_driver_data(adev);
- if (!pdata || !pdata->mmio_base || !pdata->dev_desc->ltr_required)
+ if (!pdata || !pdata->mmio_base)
return 0;
if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) {
@@ -475,12 +649,27 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
return 0;
}
- if (action == BUS_NOTIFY_ADD_DEVICE)
- ret = sysfs_create_group(&pdev->dev.kobj, &lpss_attr_group);
- else if (action == BUS_NOTIFY_DEL_DEVICE)
- sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group);
+ switch (action) {
+ case BUS_NOTIFY_BOUND_DRIVER:
+ if (pdata->dev_desc->save_ctx)
+ pdev->dev.pm_domain = &acpi_lpss_pm_domain;
+ break;
+ case BUS_NOTIFY_UNBOUND_DRIVER:
+ if (pdata->dev_desc->save_ctx)
+ pdev->dev.pm_domain = NULL;
+ break;
+ case BUS_NOTIFY_ADD_DEVICE:
+ if (pdata->dev_desc->ltr_required)
+ return sysfs_create_group(&pdev->dev.kobj,
+ &lpss_attr_group);
+ case BUS_NOTIFY_DEL_DEVICE:
+ if (pdata->dev_desc->ltr_required)
+ sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group);
+ default:
+ break;
+ }
- return ret;
+ return 0;
}
static struct notifier_block acpi_lpss_nb = {
@@ -519,3 +708,16 @@ void __init acpi_lpss_init(void)
acpi_scan_add_handler(&lpss_handler);
}
}
+
+#else
+
+static struct acpi_scan_handler lpss_handler = {
+ .ids = acpi_lpss_device_ids,
+};
+
+void __init acpi_lpss_init(void)
+{
+ acpi_scan_add_handler(&lpss_handler);
+}
+
+#endif /* CONFIG_X86_INTEL_LPSS */
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index b67be85ff0fc..23e2319ead41 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -44,6 +44,13 @@
ACPI_MODULE_NAME("acpi_memhotplug");
+static const struct acpi_device_id memory_device_ids[] = {
+ {ACPI_MEMORY_DEVICE_HID, 0},
+ {"", 0},
+};
+
+#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
+
/* Memory Device States */
#define MEMORY_INVALID_STATE 0
#define MEMORY_POWER_ON_STATE 1
@@ -53,11 +60,6 @@ static int acpi_memory_device_add(struct acpi_device *device,
const struct acpi_device_id *not_used);
static void acpi_memory_device_remove(struct acpi_device *device);
-static const struct acpi_device_id memory_device_ids[] = {
- {ACPI_MEMORY_DEVICE_HID, 0},
- {"", 0},
-};
-
static struct acpi_scan_handler memory_device_handler = {
.ids = memory_device_ids,
.attach = acpi_memory_device_add,
@@ -364,9 +366,11 @@ static bool __initdata acpi_no_memhotplug;
void __init acpi_memory_hotplug_init(void)
{
- if (acpi_no_memhotplug)
+ if (acpi_no_memhotplug) {
+ memory_device_handler.attach = NULL;
+ acpi_scan_add_handler(&memory_device_handler);
return;
-
+ }
acpi_scan_add_handler_with_hotplug(&memory_device_handler, "memory");
}
@@ -376,3 +380,16 @@ static int __init disable_acpi_memory_hotplug(char *str)
return 1;
}
__setup("acpi_no_memhotplug", disable_acpi_memory_hotplug);
+
+#else
+
+static struct acpi_scan_handler memory_device_handler = {
+ .ids = memory_device_ids,
+};
+
+void __init acpi_memory_hotplug_init(void)
+{
+ acpi_scan_add_handler(&memory_device_handler);
+}
+
+#endif /* CONFIG_ACPI_HOTPLUG_MEMORY */
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index 37d73024b82e..f148a0580e04 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -156,12 +156,13 @@ static int power_saving_thread(void *data)
while (!kthread_should_stop()) {
int cpu;
- u64 expire_time;
+ unsigned long expire_time;
try_to_freeze();
/* round robin to cpus */
- if (last_jiffies + round_robin_time * HZ < jiffies) {
+ expire_time = last_jiffies + round_robin_time * HZ;
+ if (time_before(expire_time, jiffies)) {
last_jiffies = jiffies;
round_robin_cpu(tsk_index);
}
@@ -200,7 +201,7 @@ static int power_saving_thread(void *data)
CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
local_irq_enable();
- if (jiffies > expire_time) {
+ if (time_before(expire_time, jiffies)) {
do_sleep = 1;
break;
}
@@ -215,8 +216,15 @@ static int power_saving_thread(void *data)
* borrow CPU time from this CPU and cause RT task use > 95%
* CPU time. To make 'avoid starvation' work, takes a nap here.
*/
- if (do_sleep)
+ if (unlikely(do_sleep))
schedule_timeout_killable(HZ * idle_pct / 100);
+
+ /* If an external event has set the need_resched flag, then
+ * we need to deal with it, or this loop will continue to
+ * spin without calling __mwait().
+ */
+ if (unlikely(need_resched()))
+ schedule();
}
exit_round_robin(tsk_index);
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index 1d4950388fa1..2bf9082f7523 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -22,27 +22,16 @@
ACPI_MODULE_NAME("platform");
-/*
- * The following ACPI IDs are known to be suitable for representing as
- * platform devices.
- */
-static const struct acpi_device_id acpi_platform_device_ids[] = {
-
- { "PNP0D40" },
- { "VPC2004" },
- { "BCM4752" },
-
- /* Intel Smart Sound Technology */
- { "INT33C8" },
- { "80860F28" },
-
- { }
+static const struct acpi_device_id forbidden_id_list[] = {
+ {"PNP0000", 0}, /* PIC */
+ {"PNP0100", 0}, /* Timer */
+ {"PNP0200", 0}, /* AT DMA Controller */
+ {"", 0},
};
/**
* acpi_create_platform_device - Create platform device for ACPI device node
* @adev: ACPI device node to create a platform device for.
- * @id: ACPI device ID used to match @adev.
*
* Check if the given @adev can be represented as a platform device and, if
* that's the case, create and register a platform device, populate its common
@@ -50,8 +39,7 @@ static const struct acpi_device_id acpi_platform_device_ids[] = {
*
* Name of the platform device will be the same as @adev's.
*/
-int acpi_create_platform_device(struct acpi_device *adev,
- const struct acpi_device_id *id)
+struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
{
struct platform_device *pdev = NULL;
struct acpi_device *acpi_parent;
@@ -63,19 +51,22 @@ int acpi_create_platform_device(struct acpi_device *adev,
/* If the ACPI node already has a physical device attached, skip it. */
if (adev->physical_node_count)
- return 0;
+ return NULL;
+
+ if (!acpi_match_device_ids(adev, forbidden_id_list))
+ return ERR_PTR(-EINVAL);
INIT_LIST_HEAD(&resource_list);
count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
if (count < 0) {
- return 0;
+ return NULL;
} else if (count > 0) {
resources = kmalloc(count * sizeof(struct resource),
GFP_KERNEL);
if (!resources) {
dev_err(&adev->dev, "No memory for resources\n");
acpi_dev_free_resource_list(&resource_list);
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
}
count = 0;
list_for_each_entry(rentry, &resource_list, node)
@@ -112,25 +103,13 @@ int acpi_create_platform_device(struct acpi_device *adev,
pdevinfo.num_res = count;
pdevinfo.acpi_node.companion = adev;
pdev = platform_device_register_full(&pdevinfo);
- if (IS_ERR(pdev)) {
+ if (IS_ERR(pdev))
dev_err(&adev->dev, "platform device creation failed: %ld\n",
PTR_ERR(pdev));
- pdev = NULL;
- } else {
+ else
dev_dbg(&adev->dev, "created platform device %s\n",
dev_name(&pdev->dev));
- }
kfree(resources);
- return 1;
-}
-
-static struct acpi_scan_handler platform_handler = {
- .ids = acpi_platform_device_ids,
- .attach = acpi_create_platform_device,
-};
-
-void __init acpi_platform_init(void)
-{
- acpi_scan_add_handler(&platform_handler);
+ return pdev;
}
diff --git a/drivers/acpi/acpi_pnp.c b/drivers/acpi/acpi_pnp.c
new file mode 100644
index 000000000000..6703c1fd993a
--- /dev/null
+++ b/drivers/acpi/acpi_pnp.c
@@ -0,0 +1,395 @@
+/*
+ * ACPI support for PNP bus type
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * Authors: Zhang Rui <rui.zhang@intel.com>
+ * Rafael J. Wysocki <rafael.j.wysocki@intel.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.
+ */
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+
+static const struct acpi_device_id acpi_pnp_device_ids[] = {
+ /* pata_isapnp */
+ {"PNP0600"}, /* Generic ESDI/IDE/ATA compatible hard disk controller */
+ /* floppy */
+ {"PNP0700"},
+ /* ipmi_si */
+ {"IPI0001"},
+ /* tpm_inf_pnp */
+ {"IFX0101"}, /* Infineon TPMs */
+ {"IFX0102"}, /* Infineon TPMs */
+ /*tpm_tis */
+ {"PNP0C31"}, /* TPM */
+ {"ATM1200"}, /* Atmel */
+ {"IFX0102"}, /* Infineon */
+ {"BCM0101"}, /* Broadcom */
+ {"BCM0102"}, /* Broadcom */
+ {"NSC1200"}, /* National */
+ {"ICO0102"}, /* Intel */
+ /* ide */
+ {"PNP0600"}, /* Generic ESDI/IDE/ATA compatible hard disk controller */
+ /* ns558 */
+ {"ASB16fd"}, /* AdLib NSC16 */
+ {"AZT3001"}, /* AZT1008 */
+ {"CDC0001"}, /* Opl3-SAx */
+ {"CSC0001"}, /* CS4232 */
+ {"CSC000f"}, /* CS4236 */
+ {"CSC0101"}, /* CS4327 */
+ {"CTL7001"}, /* SB16 */
+ {"CTL7002"}, /* AWE64 */
+ {"CTL7005"}, /* Vibra16 */
+ {"ENS2020"}, /* SoundscapeVIVO */
+ {"ESS0001"}, /* ES1869 */
+ {"ESS0005"}, /* ES1878 */
+ {"ESS6880"}, /* ES688 */
+ {"IBM0012"}, /* CS4232 */
+ {"OPT0001"}, /* OPTi Audio16 */
+ {"YMH0006"}, /* Opl3-SA */
+ {"YMH0022"}, /* Opl3-SAx */
+ {"PNPb02f"}, /* Generic */
+ /* i8042 kbd */
+ {"PNP0300"},
+ {"PNP0301"},
+ {"PNP0302"},
+ {"PNP0303"},
+ {"PNP0304"},
+ {"PNP0305"},
+ {"PNP0306"},
+ {"PNP0309"},
+ {"PNP030a"},
+ {"PNP030b"},
+ {"PNP0320"},
+ {"PNP0343"},
+ {"PNP0344"},
+ {"PNP0345"},
+ {"CPQA0D7"},
+ /* i8042 aux */
+ {"AUI0200"},
+ {"FJC6000"},
+ {"FJC6001"},
+ {"PNP0f03"},
+ {"PNP0f0b"},
+ {"PNP0f0e"},
+ {"PNP0f12"},
+ {"PNP0f13"},
+ {"PNP0f19"},
+ {"PNP0f1c"},
+ {"SYN0801"},
+ /* fcpnp */
+ {"AVM0900"},
+ /* radio-cadet */
+ {"MSM0c24"}, /* ADS Cadet AM/FM Radio Card */
+ /* radio-gemtek */
+ {"ADS7183"}, /* AOpen FX-3D/Pro Radio */
+ /* radio-sf16fmr2 */
+ {"MFRad13"}, /* tuner subdevice of SF16-FMD2 */
+ /* ene_ir */
+ {"ENE0100"},
+ {"ENE0200"},
+ {"ENE0201"},
+ {"ENE0202"},
+ /* fintek-cir */
+ {"FIT0002"}, /* CIR */
+ /* ite-cir */
+ {"ITE8704"}, /* Default model */
+ {"ITE8713"}, /* CIR found in EEEBox 1501U */
+ {"ITE8708"}, /* Bridged IT8512 */
+ {"ITE8709"}, /* SRAM-Bridged IT8512 */
+ /* nuvoton-cir */
+ {"WEC0530"}, /* CIR */
+ {"NTN0530"}, /* CIR for new chip's pnp id */
+ /* Winbond CIR */
+ {"WEC1022"},
+ /* wbsd */
+ {"WEC0517"},
+ {"WEC0518"},
+ /* Winbond CIR */
+ {"TCM5090"}, /* 3Com Etherlink III (TP) */
+ {"TCM5091"}, /* 3Com Etherlink III */
+ {"TCM5094"}, /* 3Com Etherlink III (combo) */
+ {"TCM5095"}, /* 3Com Etherlink III (TPO) */
+ {"TCM5098"}, /* 3Com Etherlink III (TPC) */
+ {"PNP80f7"}, /* 3Com Etherlink III compatible */
+ {"PNP80f8"}, /* 3Com Etherlink III compatible */
+ /* nsc-ircc */
+ {"NSC6001"},
+ {"HWPC224"},
+ {"IBM0071"},
+ /* smsc-ircc2 */
+ {"SMCf010"},
+ /* sb1000 */
+ {"GIC1000"},
+ /* parport_pc */
+ {"PNP0400"}, /* Standard LPT Printer Port */
+ {"PNP0401"}, /* ECP Printer Port */
+ /* apple-gmux */
+ {"APP000B"},
+ /* fujitsu-laptop.c */
+ {"FUJ02bf"},
+ {"FUJ02B1"},
+ {"FUJ02E3"},
+ /* system */
+ {"PNP0c02"}, /* General ID for reserving resources */
+ {"PNP0c01"}, /* memory controller */
+ /* rtc_cmos */
+ {"PNP0b00"},
+ {"PNP0b01"},
+ {"PNP0b02"},
+ /* c6xdigio */
+ {"PNP0400"}, /* Standard LPT Printer Port */
+ {"PNP0401"}, /* ECP Printer Port */
+ /* ni_atmio.c */
+ {"NIC1900"},
+ {"NIC2400"},
+ {"NIC2500"},
+ {"NIC2600"},
+ {"NIC2700"},
+ /* serial */
+ {"AAC000F"}, /* Archtek America Corp. Archtek SmartLink Modem 3334BT Plug & Play */
+ {"ADC0001"}, /* Anchor Datacomm BV. SXPro 144 External Data Fax Modem Plug & Play */
+ {"ADC0002"}, /* SXPro 288 External Data Fax Modem Plug & Play */
+ {"AEI0250"}, /* PROLiNK 1456VH ISA PnP K56flex Fax Modem */
+ {"AEI1240"}, /* Actiontec ISA PNP 56K X2 Fax Modem */
+ {"AKY1021"}, /* Rockwell 56K ACF II Fax+Data+Voice Modem */
+ {"AZT4001"}, /* AZT3005 PnP SOUND DEVICE */
+ {"BDP3336"}, /* Best Data Products Inc. Smart One 336F PnP Modem */
+ {"BRI0A49"}, /* Boca Complete Ofc Communicator 14.4 Data-FAX */
+ {"BRI1400"}, /* Boca Research 33,600 ACF Modem */
+ {"BRI3400"}, /* Boca 33.6 Kbps Internal FD34FSVD */
+ {"BRI0A49"}, /* Boca 33.6 Kbps Internal FD34FSVD */
+ {"BDP3336"}, /* Best Data Products Inc. Smart One 336F PnP Modem */
+ {"CPI4050"}, /* Computer Peripherals Inc. EuroViVa CommCenter-33.6 SP PnP */
+ {"CTL3001"}, /* Creative Labs Phone Blaster 28.8 DSVD PnP Voice */
+ {"CTL3011"}, /* Creative Labs Modem Blaster 28.8 DSVD PnP Voice */
+ {"DAV0336"}, /* Davicom ISA 33.6K Modem */
+ {"DMB1032"}, /* Creative Modem Blaster Flash56 DI5601-1 */
+ {"DMB2001"}, /* Creative Modem Blaster V.90 DI5660 */
+ {"ETT0002"}, /* E-Tech CyberBULLET PC56RVP */
+ {"FUJ0202"}, /* Fujitsu 33600 PnP-I2 R Plug & Play */
+ {"FUJ0205"}, /* Fujitsu FMV-FX431 Plug & Play */
+ {"FUJ0206"}, /* Fujitsu 33600 PnP-I4 R Plug & Play */
+ {"FUJ0209"}, /* Fujitsu Fax Voice 33600 PNP-I5 R Plug & Play */
+ {"GVC000F"}, /* Archtek SmartLink Modem 3334BT Plug & Play */
+ {"GVC0303"}, /* Archtek SmartLink Modem 3334BRV 33.6K Data Fax Voice */
+ {"HAY0001"}, /* Hayes Optima 288 V.34-V.FC + FAX + Voice Plug & Play */
+ {"HAY000C"}, /* Hayes Optima 336 V.34 + FAX + Voice PnP */
+ {"HAY000D"}, /* Hayes Optima 336B V.34 + FAX + Voice PnP */
+ {"HAY5670"}, /* Hayes Accura 56K Ext Fax Modem PnP */
+ {"HAY5674"}, /* Hayes Accura 56K Ext Fax Modem PnP */
+ {"HAY5675"}, /* Hayes Accura 56K Fax Modem PnP */
+ {"HAYF000"}, /* Hayes 288, V.34 + FAX */
+ {"HAYF001"}, /* Hayes Optima 288 V.34 + FAX + Voice, Plug & Play */
+ {"IBM0033"}, /* IBM Thinkpad 701 Internal Modem Voice */
+ {"PNP4972"}, /* Intermec CV60 touchscreen port */
+ {"IXDC801"}, /* Intertex 28k8 33k6 Voice EXT PnP */
+ {"IXDC901"}, /* Intertex 33k6 56k Voice EXT PnP */
+ {"IXDD801"}, /* Intertex 28k8 33k6 Voice SP EXT PnP */
+ {"IXDD901"}, /* Intertex 33k6 56k Voice SP EXT PnP */
+ {"IXDF401"}, /* Intertex 28k8 33k6 Voice SP INT PnP */
+ {"IXDF801"}, /* Intertex 28k8 33k6 Voice SP EXT PnP */
+ {"IXDF901"}, /* Intertex 33k6 56k Voice SP EXT PnP */
+ {"KOR4522"}, /* KORTEX 28800 Externe PnP */
+ {"KORF661"}, /* KXPro 33.6 Vocal ASVD PnP */
+ {"LAS4040"}, /* LASAT Internet 33600 PnP */
+ {"LAS4540"}, /* Lasat Safire 560 PnP */
+ {"LAS5440"}, /* Lasat Safire 336 PnP */
+ {"MNP0281"}, /* Microcom TravelPorte FAST V.34 Plug & Play */
+ {"MNP0336"}, /* Microcom DeskPorte V.34 FAST or FAST+ Plug & Play */
+ {"MNP0339"}, /* Microcom DeskPorte FAST EP 28.8 Plug & Play */
+ {"MNP0342"}, /* Microcom DeskPorte 28.8P Plug & Play */
+ {"MNP0500"}, /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+ {"MNP0501"}, /* Microcom DeskPorte FAST ES 28.8 Plug & Play */
+ {"MNP0502"}, /* Microcom DeskPorte 28.8S Internal Plug & Play */
+ {"MOT1105"}, /* Motorola BitSURFR Plug & Play */
+ {"MOT1111"}, /* Motorola TA210 Plug & Play */
+ {"MOT1114"}, /* Motorola HMTA 200 (ISDN) Plug & Play */
+ {"MOT1115"}, /* Motorola BitSURFR Plug & Play */
+ {"MOT1190"}, /* Motorola Lifestyle 28.8 Internal */
+ {"MOT1501"}, /* Motorola V.3400 Plug & Play */
+ {"MOT1502"}, /* Motorola Lifestyle 28.8 V.34 Plug & Play */
+ {"MOT1505"}, /* Motorola Power 28.8 V.34 Plug & Play */
+ {"MOT1509"}, /* Motorola ModemSURFR External 28.8 Plug & Play */
+ {"MOT150A"}, /* Motorola Premier 33.6 Desktop Plug & Play */
+ {"MOT150F"}, /* Motorola VoiceSURFR 56K External PnP */
+ {"MOT1510"}, /* Motorola ModemSURFR 56K External PnP */
+ {"MOT1550"}, /* Motorola ModemSURFR 56K Internal PnP */
+ {"MOT1560"}, /* Motorola ModemSURFR Internal 28.8 Plug & Play */
+ {"MOT1580"}, /* Motorola Premier 33.6 Internal Plug & Play */
+ {"MOT15B0"}, /* Motorola OnlineSURFR 28.8 Internal Plug & Play */
+ {"MOT15F0"}, /* Motorola VoiceSURFR 56K Internal PnP */
+ {"MVX00A1"}, /* Deskline K56 Phone System PnP */
+ {"MVX00F2"}, /* PC Rider K56 Phone System PnP */
+ {"nEC8241"}, /* NEC 98NOTE SPEAKER PHONE FAX MODEM(33600bps) */
+ {"PMC2430"}, /* Pace 56 Voice Internal Plug & Play Modem */
+ {"PNP0500"}, /* Generic standard PC COM port */
+ {"PNP0501"}, /* Generic 16550A-compatible COM port */
+ {"PNPC000"}, /* Compaq 14400 Modem */
+ {"PNPC001"}, /* Compaq 2400/9600 Modem */
+ {"PNPC031"}, /* Dial-Up Networking Serial Cable between 2 PCs */
+ {"PNPC032"}, /* Dial-Up Networking Parallel Cable between 2 PCs */
+ {"PNPC100"}, /* Standard 9600 bps Modem */
+ {"PNPC101"}, /* Standard 14400 bps Modem */
+ {"PNPC102"}, /* Standard 28800 bps Modem */
+ {"PNPC103"}, /* Standard Modem */
+ {"PNPC104"}, /* Standard 9600 bps Modem */
+ {"PNPC105"}, /* Standard 14400 bps Modem */
+ {"PNPC106"}, /* Standard 28800 bps Modem */
+ {"PNPC107"}, /* Standard Modem */
+ {"PNPC108"}, /* Standard 9600 bps Modem */
+ {"PNPC109"}, /* Standard 14400 bps Modem */
+ {"PNPC10A"}, /* Standard 28800 bps Modem */
+ {"PNPC10B"}, /* Standard Modem */
+ {"PNPC10C"}, /* Standard 9600 bps Modem */
+ {"PNPC10D"}, /* Standard 14400 bps Modem */
+ {"PNPC10E"}, /* Standard 28800 bps Modem */
+ {"PNPC10F"}, /* Standard Modem */
+ {"PNP2000"}, /* Standard PCMCIA Card Modem */
+ {"ROK0030"}, /* Rockwell 33.6 DPF Internal PnP, Modular Technology 33.6 Internal PnP */
+ {"ROK0100"}, /* KORTEX 14400 Externe PnP */
+ {"ROK4120"}, /* Rockwell 28.8 */
+ {"ROK4920"}, /* Viking 28.8 INTERNAL Fax+Data+Voice PnP */
+ {"RSS00A0"}, /* Rockwell 33.6 DPF External PnP, BT Prologue 33.6 External PnP, Modular Technology 33.6 External PnP */
+ {"RSS0262"}, /* Viking 56K FAX INT */
+ {"RSS0250"}, /* K56 par,VV,Voice,Speakphone,AudioSpan,PnP */
+ {"SUP1310"}, /* SupraExpress 28.8 Data/Fax PnP modem */
+ {"SUP1381"}, /* SupraExpress 336i PnP Voice Modem */
+ {"SUP1421"}, /* SupraExpress 33.6 Data/Fax PnP modem */
+ {"SUP1590"}, /* SupraExpress 33.6 Data/Fax PnP modem */
+ {"SUP1620"}, /* SupraExpress 336i Sp ASVD */
+ {"SUP1760"}, /* SupraExpress 33.6 Data/Fax PnP modem */
+ {"SUP2171"}, /* SupraExpress 56i Sp Intl */
+ {"TEX0011"}, /* Phoebe Micro 33.6 Data Fax 1433VQH Plug & Play */
+ {"UAC000F"}, /* Archtek SmartLink Modem 3334BT Plug & Play */
+ {"USR0000"}, /* 3Com Corp. Gateway Telepath IIvi 33.6 */
+ {"USR0002"}, /* U.S. Robotics Sporster 33.6K Fax INT PnP */
+ {"USR0004"}, /* Sportster Vi 14.4 PnP FAX Voicemail */
+ {"USR0006"}, /* U.S. Robotics 33.6K Voice INT PnP */
+ {"USR0007"}, /* U.S. Robotics 33.6K Voice EXT PnP */
+ {"USR0009"}, /* U.S. Robotics Courier V.Everything INT PnP */
+ {"USR2002"}, /* U.S. Robotics 33.6K Voice INT PnP */
+ {"USR2070"}, /* U.S. Robotics 56K Voice INT PnP */
+ {"USR2080"}, /* U.S. Robotics 56K Voice EXT PnP */
+ {"USR3031"}, /* U.S. Robotics 56K FAX INT */
+ {"USR3050"}, /* U.S. Robotics 56K FAX INT */
+ {"USR3070"}, /* U.S. Robotics 56K Voice INT PnP */
+ {"USR3080"}, /* U.S. Robotics 56K Voice EXT PnP */
+ {"USR3090"}, /* U.S. Robotics 56K Voice INT PnP */
+ {"USR9100"}, /* U.S. Robotics 56K Message */
+ {"USR9160"}, /* U.S. Robotics 56K FAX EXT PnP */
+ {"USR9170"}, /* U.S. Robotics 56K FAX INT PnP */
+ {"USR9180"}, /* U.S. Robotics 56K Voice EXT PnP */
+ {"USR9190"}, /* U.S. Robotics 56K Voice INT PnP */
+ {"WACFXXX"}, /* Wacom tablets */
+ {"FPI2002"}, /* Compaq touchscreen */
+ {"FUJ02B2"}, /* Fujitsu Stylistic touchscreens */
+ {"FUJ02B3"},
+ {"FUJ02B4"}, /* Fujitsu Stylistic LT touchscreens */
+ {"FUJ02B6"}, /* Passive Fujitsu Stylistic touchscreens */
+ {"FUJ02B7"},
+ {"FUJ02B8"},
+ {"FUJ02B9"},
+ {"FUJ02BC"},
+ {"FUJ02E5"}, /* Fujitsu Wacom Tablet PC device */
+ {"FUJ02E6"}, /* Fujitsu P-series tablet PC device */
+ {"FUJ02E7"}, /* Fujitsu Wacom 2FGT Tablet PC device */
+ {"FUJ02E9"}, /* Fujitsu Wacom 1FGT Tablet PC device */
+ {"LTS0001"}, /* LG C1 EXPRESS DUAL (C1-PB11A3) touch screen (actually a FUJ02E6 in disguise) */
+ {"WCI0003"}, /* Rockwell's (PORALiNK) 33600 INT PNP */
+ {"WEC1022"}, /* Winbond CIR port, should not be probed. We should keep track of it to prevent the legacy serial driver from probing it */
+ /* scl200wdt */
+ {"NSC0800"}, /* National Semiconductor PC87307/PC97307 watchdog component */
+ /* mpu401 */
+ {"PNPb006"},
+ /* cs423x-pnpbios */
+ {"CSC0100"},
+ {"CSC0000"},
+ {"GIM0100"}, /* Guillemot Turtlebeach something appears to be cs4232 compatible */
+ /* es18xx-pnpbios */
+ {"ESS1869"},
+ {"ESS1879"},
+ /* snd-opl3sa2-pnpbios */
+ {"YMH0021"},
+ {"NMX2210"}, /* Gateway Solo 2500 */
+ {""},
+};
+
+static bool is_hex_digit(char c)
+{
+ return (c >= 0 && c <= '9') || (c >= 'A' && c <= 'F');
+}
+
+static bool matching_id(char *idstr, char *list_id)
+{
+ int i;
+
+ if (memcmp(idstr, list_id, 3))
+ return false;
+
+ for (i = 3; i < 7; i++) {
+ char c = toupper(idstr[i]);
+
+ if (!is_hex_digit(c)
+ || (list_id[i] != 'X' && c != toupper(list_id[i])))
+ return false;
+ }
+ return true;
+}
+
+static bool acpi_pnp_match(char *idstr, const struct acpi_device_id **matchid)
+{
+ const struct acpi_device_id *devid;
+
+ for (devid = acpi_pnp_device_ids; devid->id[0]; devid++)
+ if (matching_id(idstr, (char *)devid->id)) {
+ if (matchid)
+ *matchid = devid;
+
+ return true;
+ }
+
+ return false;
+}
+
+static int acpi_pnp_attach(struct acpi_device *adev,
+ const struct acpi_device_id *id)
+{
+ return 1;
+}
+
+static struct acpi_scan_handler acpi_pnp_handler = {
+ .ids = acpi_pnp_device_ids,
+ .match = acpi_pnp_match,
+ .attach = acpi_pnp_attach,
+};
+
+/*
+ * For CMOS RTC devices, the PNP ACPI scan handler does not work, because
+ * there is a CMOS RTC ACPI scan handler installed already, so we need to
+ * check those devices and enumerate them to the PNP bus directly.
+ */
+static int is_cmos_rtc_device(struct acpi_device *adev)
+{
+ struct acpi_device_id ids[] = {
+ { "PNP0B00" },
+ { "PNP0B01" },
+ { "PNP0B02" },
+ {""},
+ };
+ return !acpi_match_device_ids(adev, ids);
+}
+
+bool acpi_is_pnp_device(struct acpi_device *adev)
+{
+ return adev->handler == &acpi_pnp_handler || is_cmos_rtc_device(adev);
+}
+EXPORT_SYMBOL_GPL(acpi_is_pnp_device);
+
+void __init acpi_pnp_init(void)
+{
+ acpi_scan_add_handler(&acpi_pnp_handler);
+}
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index 52c81c49cc7d..1c085742644f 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -268,7 +268,7 @@ static int acpi_processor_get_info(struct acpi_device *device)
pr->apic_id = apic_id;
cpu_index = acpi_map_cpuid(pr->apic_id, pr->acpi_id);
- if (!cpu0_initialized) {
+ if (!cpu0_initialized && !acpi_lapic) {
cpu0_initialized = 1;
/* Handle UP system running SMP kernel, with no LAPIC in MADT */
if ((cpu_index == -1) && (num_online_cpus() == 1))
diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile
index b7ed86a20427..8bb43f06e11f 100644
--- a/drivers/acpi/acpica/Makefile
+++ b/drivers/acpi/acpica/Makefile
@@ -135,6 +135,7 @@ acpi-y += \
rsxface.o
acpi-y += \
+ tbdata.o \
tbfadt.o \
tbfind.o \
tbinstal.o \
diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h
new file mode 100644
index 000000000000..8698ffba6f39
--- /dev/null
+++ b/drivers/acpi/acpica/acapps.h
@@ -0,0 +1,170 @@
+/******************************************************************************
+ *
+ * Module Name: acapps - common include for ACPI applications/tools
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2014, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#ifndef _ACAPPS
+#define _ACAPPS
+
+/* Common info for tool signons */
+
+#define ACPICA_NAME "Intel ACPI Component Architecture"
+#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2014 Intel Corporation"
+
+#if ACPI_MACHINE_WIDTH == 64
+#define ACPI_WIDTH "-64"
+
+#elif ACPI_MACHINE_WIDTH == 32
+#define ACPI_WIDTH "-32"
+
+#else
+#error unknown ACPI_MACHINE_WIDTH
+#define ACPI_WIDTH "-??"
+
+#endif
+
+/* Macros for signons and file headers */
+
+#define ACPI_COMMON_SIGNON(utility_name) \
+ "\n%s\n%s version %8.8X%s [%s]\n%s\n\n", \
+ ACPICA_NAME, \
+ utility_name, ((u32) ACPI_CA_VERSION), ACPI_WIDTH, __DATE__, \
+ ACPICA_COPYRIGHT
+
+#define ACPI_COMMON_HEADER(utility_name, prefix) \
+ "%s%s\n%s%s version %8.8X%s [%s]\n%s%s\n%s\n", \
+ prefix, ACPICA_NAME, \
+ prefix, utility_name, ((u32) ACPI_CA_VERSION), ACPI_WIDTH, __DATE__, \
+ prefix, ACPICA_COPYRIGHT, \
+ prefix
+
+/* Macros for usage messages */
+
+#define ACPI_USAGE_HEADER(usage) \
+ printf ("Usage: %s\nOptions:\n", usage);
+
+#define ACPI_OPTION(name, description) \
+ printf (" %-18s%s\n", name, description);
+
+#define FILE_SUFFIX_DISASSEMBLY "dsl"
+#define ACPI_TABLE_FILE_SUFFIX ".dat"
+
+/*
+ * getopt
+ */
+int acpi_getopt(int argc, char **argv, char *opts);
+
+int acpi_getopt_argument(int argc, char **argv);
+
+extern int acpi_gbl_optind;
+extern int acpi_gbl_opterr;
+extern int acpi_gbl_sub_opt_char;
+extern char *acpi_gbl_optarg;
+
+/*
+ * cmfsize - Common get file size function
+ */
+u32 cm_get_file_size(FILE * file);
+
+#ifndef ACPI_DUMP_APP
+/*
+ * adisasm
+ */
+acpi_status
+ad_aml_disassemble(u8 out_to_file,
+ char *filename, char *prefix, char **out_filename);
+
+void ad_print_statistics(void);
+
+acpi_status ad_find_dsdt(u8 **dsdt_ptr, u32 *dsdt_length);
+
+void ad_dump_tables(void);
+
+acpi_status ad_get_local_tables(void);
+
+acpi_status
+ad_parse_table(struct acpi_table_header *table,
+ acpi_owner_id * owner_id, u8 load_table, u8 external);
+
+acpi_status ad_display_tables(char *filename, struct acpi_table_header *table);
+
+acpi_status ad_display_statistics(void);
+
+/*
+ * adwalk
+ */
+void
+acpi_dm_cross_reference_namespace(union acpi_parse_object *parse_tree_root,
+ struct acpi_namespace_node *namespace_root,
+ acpi_owner_id owner_id);
+
+void acpi_dm_dump_tree(union acpi_parse_object *origin);
+
+void acpi_dm_find_orphan_methods(union acpi_parse_object *origin);
+
+void
+acpi_dm_finish_namespace_load(union acpi_parse_object *parse_tree_root,
+ struct acpi_namespace_node *namespace_root,
+ acpi_owner_id owner_id);
+
+void
+acpi_dm_convert_resource_indexes(union acpi_parse_object *parse_tree_root,
+ struct acpi_namespace_node *namespace_root);
+
+/*
+ * adfile
+ */
+acpi_status ad_initialize(void);
+
+char *fl_generate_filename(char *input_filename, char *suffix);
+
+acpi_status
+fl_split_input_pathname(char *input_path,
+ char **out_directory_path, char **out_filename);
+
+char *ad_generate_filename(char *prefix, char *table_id);
+
+void
+ad_write_table(struct acpi_table_header *table,
+ u32 length, char *table_name, char *oem_table_id);
+#endif
+
+#endif /* _ACAPPS */
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index 68ec61fff188..7a7811a9fc26 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -104,9 +104,10 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info *gpe_event_info);
*/
acpi_status
acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
- struct acpi_generic_address *gpe_block_address,
+ u64 address,
+ u8 space_id,
u32 register_count,
- u8 gpe_block_base_number,
+ u16 gpe_block_base_number,
u32 interrupt_number,
struct acpi_gpe_block_info **return_gpe_block);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index a08a448068dd..115eedcade1e 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -44,144 +44,14 @@
#ifndef __ACGLOBAL_H__
#define __ACGLOBAL_H__
-/*
- * Ensure that the globals are actually defined and initialized only once.
- *
- * The use of these macros allows a single list of globals (here) in order
- * to simplify maintenance of the code.
- */
-#ifdef DEFINE_ACPI_GLOBALS
-#define ACPI_GLOBAL(type,name) \
- extern type name; \
- type name
-
-#define ACPI_INIT_GLOBAL(type,name,value) \
- type name=value
-
-#else
-#define ACPI_GLOBAL(type,name) \
- extern type name
-
-#define ACPI_INIT_GLOBAL(type,name,value) \
- extern type name
-#endif
-
-#ifdef DEFINE_ACPI_GLOBALS
-
-/* Public globals, available from outside ACPICA subsystem */
-
/*****************************************************************************
*
- * Runtime configuration (static defaults that can be overriden at runtime)
+ * Globals related to the ACPI tables
*
****************************************************************************/
-/*
- * Enable "slack" in the AML interpreter? Default is FALSE, and the
- * interpreter strictly follows the ACPI specification. Setting to TRUE
- * allows the interpreter to ignore certain errors and/or bad AML constructs.
- *
- * Currently, these features are enabled by this flag:
- *
- * 1) Allow "implicit return" of last value in a control method
- * 2) Allow access beyond the end of an operation region
- * 3) Allow access to uninitialized locals/args (auto-init to integer 0)
- * 4) Allow ANY object type to be a source operand for the Store() operator
- * 5) Allow unresolved references (invalid target name) in package objects
- * 6) Enable warning messages for behavior that is not ACPI spec compliant
- */
-ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_interpreter_slack, FALSE);
+/* Master list of all ACPI tables that were found in the RSDT/XSDT */
-/*
- * Automatically serialize all methods that create named objects? Default
- * is TRUE, meaning that all non_serialized methods are scanned once at
- * table load time to determine those that create named objects. Methods
- * that create named objects are marked Serialized in order to prevent
- * possible run-time problems if they are entered by more than one thread.
- */
-ACPI_INIT_GLOBAL(u8, acpi_gbl_auto_serialize_methods, TRUE);
-
-/*
- * Create the predefined _OSI method in the namespace? Default is TRUE
- * because ACPI CA is fully compatible with other ACPI implementations.
- * Changing this will revert ACPI CA (and machine ASL) to pre-OSI behavior.
- */
-ACPI_INIT_GLOBAL(u8, acpi_gbl_create_osi_method, TRUE);
-
-/*
- * Optionally use default values for the ACPI register widths. Set this to
- * TRUE to use the defaults, if an FADT contains incorrect widths/lengths.
- */
-ACPI_INIT_GLOBAL(u8, acpi_gbl_use_default_register_widths, TRUE);
-
-/*
- * Optionally enable output from the AML Debug Object.
- */
-ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_aml_debug_object, FALSE);
-
-/*
- * Optionally copy the entire DSDT to local memory (instead of simply
- * mapping it.) There are some BIOSs that corrupt or replace the original
- * DSDT, creating the need for this option. Default is FALSE, do not copy
- * the DSDT.
- */
-ACPI_INIT_GLOBAL(u8, acpi_gbl_copy_dsdt_locally, FALSE);
-
-/*
- * Optionally ignore an XSDT if present and use the RSDT instead.
- * Although the ACPI specification requires that an XSDT be used instead
- * of the RSDT, the XSDT has been found to be corrupt or ill-formed on
- * some machines. Default behavior is to use the XSDT if present.
- */
-ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE);
-
-/*
- * Optionally use 32-bit FADT addresses if and when there is a conflict
- * (address mismatch) between the 32-bit and 64-bit versions of the
- * address. Although ACPICA adheres to the ACPI specification which
- * requires the use of the corresponding 64-bit address if it is non-zero,
- * some machines have been found to have a corrupted non-zero 64-bit
- * address. Default is TRUE, favor the 32-bit addresses.
- */
-ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_fadt_addresses, TRUE);
-
-/*
- * Optionally truncate I/O addresses to 16 bits. Provides compatibility
- * with other ACPI implementations. NOTE: During ACPICA initialization,
- * this value is set to TRUE if any Windows OSI strings have been
- * requested by the BIOS.
- */
-ACPI_INIT_GLOBAL(u8, acpi_gbl_truncate_io_addresses, FALSE);
-
-/*
- * Disable runtime checking and repair of values returned by control methods.
- * Use only if the repair is causing a problem on a particular machine.
- */
-ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_auto_repair, FALSE);
-
-/*
- * Optionally do not load any SSDTs from the RSDT/XSDT during initialization.
- * This can be useful for debugging ACPI problems on some machines.
- */
-ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_load, FALSE);
-
-/*
- * We keep track of the latest version of Windows that has been requested by
- * the BIOS.
- */
-ACPI_INIT_GLOBAL(u8, acpi_gbl_osi_data, 0);
-
-#endif /* DEFINE_ACPI_GLOBALS */
-
-/*****************************************************************************
- *
- * ACPI Table globals
- *
- ****************************************************************************/
-
-/*
- * Master list of all ACPI tables that were found in the RSDT/XSDT.
- */
ACPI_GLOBAL(struct acpi_table_list, acpi_gbl_root_table_list);
/* DSDT information. Used to check for DSDT corruption */
@@ -279,7 +149,6 @@ ACPI_GLOBAL(acpi_exception_handler, acpi_gbl_exception_handler);
ACPI_GLOBAL(acpi_init_handler, acpi_gbl_init_handler);
ACPI_GLOBAL(acpi_table_handler, acpi_gbl_table_handler);
ACPI_GLOBAL(void *, acpi_gbl_table_handler_context);
-ACPI_GLOBAL(struct acpi_walk_state *, acpi_gbl_breakpoint_walk);
ACPI_GLOBAL(acpi_interface_handler, acpi_gbl_interface_handler);
ACPI_GLOBAL(struct acpi_sci_handler_info *, acpi_gbl_sci_handler_list);
@@ -296,7 +165,6 @@ ACPI_GLOBAL(u8, acpi_gbl_reg_methods_executed);
/* Misc */
ACPI_GLOBAL(u32, acpi_gbl_original_mode);
-ACPI_GLOBAL(u32, acpi_gbl_rsdp_original_location);
ACPI_GLOBAL(u32, acpi_gbl_ns_lookup_count);
ACPI_GLOBAL(u32, acpi_gbl_ps_find_count);
ACPI_GLOBAL(u16, acpi_gbl_pm1_enable_register_save);
@@ -483,11 +351,6 @@ ACPI_GLOBAL(u16, acpi_gbl_node_type_count_misc);
ACPI_GLOBAL(u32, acpi_gbl_num_nodes);
ACPI_GLOBAL(u32, acpi_gbl_num_objects);
-ACPI_GLOBAL(u32, acpi_gbl_size_of_parse_tree);
-ACPI_GLOBAL(u32, acpi_gbl_size_of_method_trees);
-ACPI_GLOBAL(u32, acpi_gbl_size_of_node_entries);
-ACPI_GLOBAL(u32, acpi_gbl_size_of_acpi_objects);
-
#endif /* ACPI_DEBUGGER */
/*****************************************************************************
@@ -509,5 +372,6 @@ ACPI_INIT_GLOBAL(ACPI_FILE, acpi_gbl_debug_file, NULL);
****************************************************************************/
extern const struct ah_predefined_name asl_predefined_info[];
+extern const struct ah_device_id asl_device_ids[];
#endif /* __ACGLOBAL_H__ */
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 52a21dafb540..91f801a2e689 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -450,9 +450,9 @@ struct acpi_gpe_event_info {
struct acpi_gpe_register_info {
struct acpi_generic_address status_address; /* Address of status reg */
struct acpi_generic_address enable_address; /* Address of enable reg */
+ u16 base_gpe_number; /* Base GPE number for this register */
u8 enable_for_wake; /* GPEs to keep enabled when sleeping */
u8 enable_for_run; /* GPEs to keep enabled when running */
- u8 base_gpe_number; /* Base GPE number for this register */
};
/*
@@ -466,11 +466,12 @@ struct acpi_gpe_block_info {
struct acpi_gpe_xrupt_info *xrupt_block; /* Backpointer to interrupt block */
struct acpi_gpe_register_info *register_info; /* One per GPE register pair */
struct acpi_gpe_event_info *event_info; /* One for each GPE */
- struct acpi_generic_address block_address; /* Base address of the block */
+ u64 address; /* Base address of the block */
u32 register_count; /* Number of register pairs in block */
u16 gpe_count; /* Number of individual GPEs in block */
- u8 block_base_number; /* Base GPE number for this block */
- u8 initialized; /* TRUE if this block is initialized */
+ u16 block_base_number; /* Base GPE number for this block */
+ u8 space_id;
+ u8 initialized; /* TRUE if this block is initialized */
};
/* Information about GPE interrupt handlers, one per each interrupt level used for GPEs */
@@ -733,7 +734,8 @@ union acpi_parse_value {
#define ACPI_DASM_MATCHOP 0x06 /* Parent opcode is a Match() operator */
#define ACPI_DASM_LNOT_PREFIX 0x07 /* Start of a Lnot_equal (etc.) pair of opcodes */
#define ACPI_DASM_LNOT_SUFFIX 0x08 /* End of a Lnot_equal (etc.) pair of opcodes */
-#define ACPI_DASM_IGNORE 0x09 /* Not used at this time */
+#define ACPI_DASM_HID_STRING 0x09 /* String is a _HID or _CID */
+#define ACPI_DASM_IGNORE 0x0A /* Not used at this time */
/*
* Generic operation (for example: If, While, Store)
@@ -1147,4 +1149,9 @@ struct ah_predefined_name {
#endif
};
+struct ah_device_id {
+ char *name;
+ char *description;
+};
+
#endif /* __ACLOCAL_H__ */
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index a48d713e9599..bd08817cafd8 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -586,6 +586,10 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
{{"_LID", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+ {{"_LPD", METHOD_0ARGS,
+ METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (2 Int) */
+ PACKAGE_INFO(ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_INTEGER, 2, 0, 0, 0),
+
{{"_MAT", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
@@ -698,12 +702,6 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
- {{"_PRP", METHOD_0ARGS,
- METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: 1 Str, 1 Int/Str/Pkg */
- PACKAGE_INFO(ACPI_PTYPE2, ACPI_RTYPE_STRING, 1,
- ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING |
- ACPI_RTYPE_PACKAGE | ACPI_RTYPE_REFERENCE, 1, 0),
-
{{"_PRS", METHOD_0ARGS,
METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h
index 5fa4b2027697..f14882788eee 100644
--- a/drivers/acpi/acpica/actables.h
+++ b/drivers/acpi/acpica/actables.h
@@ -54,6 +54,31 @@ acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);
u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length);
/*
+ * tbdata - table data structure management
+ */
+acpi_status acpi_tb_get_next_root_index(u32 *table_index);
+
+void
+acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc,
+ acpi_physical_address address,
+ u8 flags, struct acpi_table_header *table);
+
+acpi_status
+acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc,
+ acpi_physical_address address, u8 flags);
+
+void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc);
+
+acpi_status acpi_tb_validate_temp_table(struct acpi_table_desc *table_desc);
+
+acpi_status
+acpi_tb_verify_temp_table(struct acpi_table_desc *table_desc, char *signature);
+
+u8 acpi_tb_is_table_loaded(u32 table_index);
+
+void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded);
+
+/*
* tbfadt - FADT parse/convert/validate
*/
void acpi_tb_parse_fadt(u32 table_index);
@@ -72,22 +97,32 @@ acpi_tb_find_table(char *signature,
*/
acpi_status acpi_tb_resize_root_table_list(void);
-acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc);
+acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc);
+
+void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc);
+
+void acpi_tb_override_table(struct acpi_table_desc *old_table_desc);
-struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header
- *table_header,
- struct acpi_table_desc
- *table_desc);
+acpi_status
+acpi_tb_acquire_table(struct acpi_table_desc *table_desc,
+ struct acpi_table_header **table_ptr,
+ u32 *table_length, u8 *table_flags);
+
+void
+acpi_tb_release_table(struct acpi_table_header *table,
+ u32 table_length, u8 table_flags);
acpi_status
-acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index);
+acpi_tb_install_standard_table(acpi_physical_address address,
+ u8 flags,
+ u8 reload, u8 override, u32 *table_index);
acpi_status
acpi_tb_store_table(acpi_physical_address address,
struct acpi_table_header *table,
u32 length, u8 flags, u32 *table_index);
-void acpi_tb_delete_table(struct acpi_table_desc *table_desc);
+void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc);
void acpi_tb_terminate(void);
@@ -99,10 +134,6 @@ acpi_status acpi_tb_release_owner_id(u32 table_index);
acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id *owner_id);
-u8 acpi_tb_is_table_loaded(u32 table_index);
-
-void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded);
-
/*
* tbutils - table manager utilities
*/
@@ -124,8 +155,13 @@ void acpi_tb_check_dsdt_header(void);
struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index);
void
-acpi_tb_install_table(acpi_physical_address address,
- char *signature, u32 table_index);
+acpi_tb_install_table_with_override(u32 table_index,
+ struct acpi_table_desc *new_table_desc,
+ u8 override);
+
+acpi_status
+acpi_tb_install_fixed_table(acpi_physical_address address,
+ char *signature, u32 table_index);
acpi_status acpi_tb_parse_root_table(acpi_physical_address rsdp_address);
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index ceeec0b7ccb1..1e256c5bda20 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -176,8 +176,7 @@ acpi_status acpi_ut_init_globals(void);
char *acpi_ut_get_mutex_name(u32 mutex_id);
-const char *acpi_ut_get_notify_name(u32 notify_value);
-
+const char *acpi_ut_get_notify_name(u32 notify_value, acpi_object_type type);
#endif
char *acpi_ut_get_type_name(acpi_object_type type);
@@ -737,4 +736,11 @@ acpi_ut_method_error(const char *module_name,
struct acpi_namespace_node *node,
const char *path, acpi_status lookup_status);
+/*
+ * Utility functions for ACPI names and IDs
+ */
+const struct ah_predefined_name *acpi_ah_match_predefined_name(char *nameseg);
+
+const struct ah_device_id *acpi_ah_match_hardware_id(char *hid);
+
#endif /* _ACUTILS_H */
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index 955f83da68a5..48f70013b488 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -383,7 +383,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
if (!(gpe_register_info->enable_for_run |
gpe_register_info->enable_for_wake)) {
ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS,
- "Ignore disabled registers for GPE%02X-GPE%02X: "
+ "Ignore disabled registers for GPE %02X-%02X: "
"RunEnable=%02X, WakeEnable=%02X\n",
gpe_register_info->
base_gpe_number,
@@ -416,7 +416,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
}
ACPI_DEBUG_PRINT((ACPI_DB_INTERRUPTS,
- "Read registers for GPE%02X-GPE%02X: Status=%02X, Enable=%02X, "
+ "Read registers for GPE %02X-%02X: Status=%02X, Enable=%02X, "
"RunEnable=%02X, WakeEnable=%02X\n",
gpe_register_info->base_gpe_number,
gpe_register_info->base_gpe_number +
@@ -706,7 +706,8 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
status = acpi_hw_clear_gpe(gpe_event_info);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "Unable to clear GPE%02X", gpe_number));
+ "Unable to clear GPE %02X",
+ gpe_number));
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
}
}
@@ -723,7 +724,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "Unable to disable GPE%02X", gpe_number));
+ "Unable to disable GPE %02X", gpe_number));
return_UINT32(ACPI_INTERRUPT_NOT_HANDLED);
}
@@ -764,7 +765,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
gpe_event_info);
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
- "Unable to queue handler for GPE%02X - event disabled",
+ "Unable to queue handler for GPE %02X - event disabled",
gpe_number));
}
break;
@@ -776,7 +777,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
* a GPE to be enabled if it has no handler or method.
*/
ACPI_ERROR((AE_INFO,
- "No handler or method for GPE%02X, disabling event",
+ "No handler or method for GPE %02X, disabling event",
gpe_number));
break;
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index caaed3c673fd..d86699eea33c 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -252,21 +252,17 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
/* Init the register_info for this GPE register (8 GPEs) */
- this_register->base_gpe_number =
- (u8) (gpe_block->block_base_number +
- (i * ACPI_GPE_REGISTER_WIDTH));
+ this_register->base_gpe_number = (u16)
+ (gpe_block->block_base_number +
+ (i * ACPI_GPE_REGISTER_WIDTH));
- this_register->status_address.address =
- gpe_block->block_address.address + i;
+ this_register->status_address.address = gpe_block->address + i;
this_register->enable_address.address =
- gpe_block->block_address.address + i +
- gpe_block->register_count;
+ gpe_block->address + i + gpe_block->register_count;
- this_register->status_address.space_id =
- gpe_block->block_address.space_id;
- this_register->enable_address.space_id =
- gpe_block->block_address.space_id;
+ this_register->status_address.space_id = gpe_block->space_id;
+ this_register->enable_address.space_id = gpe_block->space_id;
this_register->status_address.bit_width =
ACPI_GPE_REGISTER_WIDTH;
this_register->enable_address.bit_width =
@@ -334,9 +330,10 @@ error_exit:
acpi_status
acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
- struct acpi_generic_address *gpe_block_address,
+ u64 address,
+ u8 space_id,
u32 register_count,
- u8 gpe_block_base_number,
+ u16 gpe_block_base_number,
u32 interrupt_number,
struct acpi_gpe_block_info **return_gpe_block)
{
@@ -359,15 +356,14 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
/* Initialize the new GPE block */
+ gpe_block->address = address;
+ gpe_block->space_id = space_id;
gpe_block->node = gpe_device;
gpe_block->gpe_count = (u16)(register_count * ACPI_GPE_REGISTER_WIDTH);
gpe_block->initialized = FALSE;
gpe_block->register_count = register_count;
gpe_block->block_base_number = gpe_block_base_number;
- ACPI_MEMCPY(&gpe_block->block_address, gpe_block_address,
- sizeof(struct acpi_generic_address));
-
/*
* Create the register_info and event_info sub-structures
* Note: disables and clears all GPEs in the block
@@ -408,12 +404,14 @@ acpi_ev_create_gpe_block(struct acpi_namespace_node *gpe_device,
}
ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
- " Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X\n",
+ " Initialized GPE %02X to %02X [%4.4s] %u regs on interrupt 0x%X%s\n",
(u32)gpe_block->block_base_number,
(u32)(gpe_block->block_base_number +
(gpe_block->gpe_count - 1)),
gpe_device->name.ascii, gpe_block->register_count,
- interrupt_number));
+ interrupt_number,
+ interrupt_number ==
+ acpi_gbl_FADT.sci_interrupt ? " (SCI)" : ""));
/* Update global count of currently available GPEs */
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index ae779c1e871d..49fc7effd961 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -131,8 +131,10 @@ acpi_status acpi_ev_gpe_initialize(void)
/* Install GPE Block 0 */
status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
- &acpi_gbl_FADT.xgpe0_block,
- register_count0, 0,
+ acpi_gbl_FADT.xgpe0_block.
+ address,
+ acpi_gbl_FADT.xgpe0_block.
+ space_id, register_count0, 0,
acpi_gbl_FADT.sci_interrupt,
&acpi_gbl_gpe_fadt_blocks[0]);
@@ -169,8 +171,10 @@ acpi_status acpi_ev_gpe_initialize(void)
status =
acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
- &acpi_gbl_FADT.xgpe1_block,
- register_count1,
+ acpi_gbl_FADT.xgpe1_block.
+ address,
+ acpi_gbl_FADT.xgpe1_block.
+ space_id, register_count1,
acpi_gbl_FADT.gpe1_base,
acpi_gbl_FADT.
sci_interrupt,
diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c
index 5d594eb2e5ec..24ea3424981b 100644
--- a/drivers/acpi/acpica/evmisc.c
+++ b/drivers/acpi/acpica/evmisc.c
@@ -167,7 +167,8 @@ acpi_ev_queue_notify_request(struct acpi_namespace_node * node,
"Dispatching Notify on [%4.4s] (%s) Value 0x%2.2X (%s) Node %p\n",
acpi_ut_get_node_name(node),
acpi_ut_get_type_name(node->type), notify_value,
- acpi_ut_get_notify_name(notify_value), node));
+ acpi_ut_get_notify_name(notify_value, ACPI_TYPE_ANY),
+ node));
status = acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_notify_dispatch,
info);
diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c
index 4d8a709c1fc4..29630e303829 100644
--- a/drivers/acpi/acpica/evsci.c
+++ b/drivers/acpi/acpica/evsci.c
@@ -117,7 +117,7 @@ static u32 ACPI_SYSTEM_XFACE acpi_ev_sci_xrupt_handler(void *context)
ACPI_FUNCTION_TRACE(ev_sci_xrupt_handler);
/*
- * We are guaranteed by the ACPI CA initialization/shutdown code that
+ * We are guaranteed by the ACPICA initialization/shutdown code that
* if this interrupt handler is installed, ACPI is enabled.
*/
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index a734b27da061..11e5803b8b41 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -239,7 +239,7 @@ acpi_remove_notify_handler(acpi_handle device,
union acpi_operand_object *obj_desc;
union acpi_operand_object *handler_obj;
union acpi_operand_object *previous_handler_obj;
- acpi_status status;
+ acpi_status status = AE_OK;
u32 i;
ACPI_FUNCTION_TRACE(acpi_remove_notify_handler);
@@ -251,20 +251,17 @@ acpi_remove_notify_handler(acpi_handle device,
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Make sure all deferred notify tasks are completed */
-
- acpi_os_wait_events_complete();
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
-
/* Root Object. Global handlers are removed here */
if (device == ACPI_ROOT_OBJECT) {
for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
if (handler_type & (i + 1)) {
+ status =
+ acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
if (!acpi_gbl_global_notify[i].handler ||
(acpi_gbl_global_notify[i].handler !=
handler)) {
@@ -277,31 +274,40 @@ acpi_remove_notify_handler(acpi_handle device,
acpi_gbl_global_notify[i].handler = NULL;
acpi_gbl_global_notify[i].context = NULL;
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+
+ /* Make sure all deferred notify tasks are completed */
+
+ acpi_os_wait_events_complete();
}
}
- goto unlock_and_exit;
+ return_ACPI_STATUS(AE_OK);
}
/* All other objects: Are Notifies allowed on this object? */
if (!acpi_ev_is_notify_object(node)) {
- status = AE_TYPE;
- goto unlock_and_exit;
+ return_ACPI_STATUS(AE_TYPE);
}
/* Must have an existing internal object */
obj_desc = acpi_ns_get_attached_object(node);
if (!obj_desc) {
- status = AE_NOT_EXIST;
- goto unlock_and_exit;
+ return_ACPI_STATUS(AE_NOT_EXIST);
}
/* Internal object exists. Find the handler and remove it */
for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
if (handler_type & (i + 1)) {
+ status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
handler_obj = obj_desc->common_notify.notify_list[i];
previous_handler_obj = NULL;
@@ -329,10 +335,17 @@ acpi_remove_notify_handler(acpi_handle device,
handler_obj->notify.next[i];
}
+ (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
+
+ /* Make sure all deferred notify tasks are completed */
+
+ acpi_os_wait_events_complete();
acpi_ut_remove_reference(handler_obj);
}
}
+ return_ACPI_STATUS(status);
+
unlock_and_exit:
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
return_ACPI_STATUS(status);
@@ -457,6 +470,8 @@ exit:
return_ACPI_STATUS(status);
}
+ACPI_EXPORT_SYMBOL(acpi_install_sci_handler)
+
/*******************************************************************************
*
* FUNCTION: acpi_remove_sci_handler
@@ -468,7 +483,6 @@ exit:
* DESCRIPTION: Remove a handler for a System Control Interrupt.
*
******************************************************************************/
-
acpi_status acpi_remove_sci_handler(acpi_sci_handler address)
{
struct acpi_sci_handler_info *prev_sci_handler;
@@ -522,6 +536,8 @@ unlock_and_exit:
return_ACPI_STATUS(status);
}
+ACPI_EXPORT_SYMBOL(acpi_remove_sci_handler)
+
/*******************************************************************************
*
* FUNCTION: acpi_install_global_event_handler
@@ -537,7 +553,6 @@ unlock_and_exit:
* Can be used to update event counters, etc.
*
******************************************************************************/
-
acpi_status
acpi_install_global_event_handler(acpi_gbl_event_handler handler, void *context)
{
@@ -840,10 +855,6 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Make sure all deferred GPE tasks are completed */
-
- acpi_os_wait_events_complete();
-
status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -895,9 +906,17 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
(void)acpi_ev_add_gpe_reference(gpe_event_info);
}
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
+
+ /* Make sure all deferred GPE tasks are completed */
+
+ acpi_os_wait_events_complete();
+
/* Now we can free the handler object */
ACPI_FREE(handler);
+ return_ACPI_STATUS(status);
unlock_and_exit:
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index 20a1392ffe06..cb534faf5369 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -599,9 +599,10 @@ acpi_install_gpe_block(acpi_handle gpe_device,
* For user-installed GPE Block Devices, the gpe_block_base_number
* is always zero
*/
- status =
- acpi_ev_create_gpe_block(node, gpe_block_address, register_count, 0,
- interrupt_number, &gpe_block);
+ status = acpi_ev_create_gpe_block(node, gpe_block_address->address,
+ gpe_block_address->space_id,
+ register_count, 0, interrupt_number,
+ &gpe_block);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c
index 8ba1464efd11..7d2949420db7 100644
--- a/drivers/acpi/acpica/exconfig.c
+++ b/drivers/acpi/acpica/exconfig.c
@@ -343,16 +343,14 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state)
{
union acpi_operand_object *ddb_handle;
+ struct acpi_table_header *table_header;
struct acpi_table_header *table;
- struct acpi_table_desc table_desc;
u32 table_index;
acpi_status status;
u32 length;
ACPI_FUNCTION_TRACE(ex_load_op);
- ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
-
/* Source Object can be either an op_region or a Buffer/Field */
switch (obj_desc->common.type) {
@@ -380,17 +378,17 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/* Get the table header first so we can get the table length */
- table = ACPI_ALLOCATE(sizeof(struct acpi_table_header));
- if (!table) {
+ table_header = ACPI_ALLOCATE(sizeof(struct acpi_table_header));
+ if (!table_header) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
status =
acpi_ex_region_read(obj_desc,
sizeof(struct acpi_table_header),
- ACPI_CAST_PTR(u8, table));
- length = table->length;
- ACPI_FREE(table);
+ ACPI_CAST_PTR(u8, table_header));
+ length = table_header->length;
+ ACPI_FREE(table_header);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
@@ -420,22 +418,19 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/* Allocate a buffer for the table */
- table_desc.pointer = ACPI_ALLOCATE(length);
- if (!table_desc.pointer) {
+ table = ACPI_ALLOCATE(length);
+ if (!table) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
/* Read the entire table */
status = acpi_ex_region_read(obj_desc, length,
- ACPI_CAST_PTR(u8,
- table_desc.pointer));
+ ACPI_CAST_PTR(u8, table));
if (ACPI_FAILURE(status)) {
- ACPI_FREE(table_desc.pointer);
+ ACPI_FREE(table);
return_ACPI_STATUS(status);
}
-
- table_desc.address = obj_desc->region.address;
break;
case ACPI_TYPE_BUFFER: /* Buffer or resolved region_field */
@@ -452,10 +447,10 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/* Get the actual table length from the table header */
- table =
+ table_header =
ACPI_CAST_PTR(struct acpi_table_header,
obj_desc->buffer.pointer);
- length = table->length;
+ length = table_header->length;
/* Table cannot extend beyond the buffer */
@@ -470,13 +465,12 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
* Copy the table from the buffer because the buffer could be modified
* or even deleted in the future
*/
- table_desc.pointer = ACPI_ALLOCATE(length);
- if (!table_desc.pointer) {
+ table = ACPI_ALLOCATE(length);
+ if (!table) {
return_ACPI_STATUS(AE_NO_MEMORY);
}
- ACPI_MEMCPY(table_desc.pointer, table, length);
- table_desc.address = ACPI_TO_INTEGER(table_desc.pointer);
+ ACPI_MEMCPY(table, table_header, length);
break;
default:
@@ -484,27 +478,32 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
}
- /* Validate table checksum (will not get validated in tb_add_table) */
-
- status = acpi_tb_verify_checksum(table_desc.pointer, length);
- if (ACPI_FAILURE(status)) {
- ACPI_FREE(table_desc.pointer);
- return_ACPI_STATUS(status);
- }
-
- /* Complete the table descriptor */
+ /* Install the new table into the local data structures */
- table_desc.length = length;
- table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
+ ACPI_INFO((AE_INFO, "Dynamic OEM Table Load:"));
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- /* Install the new table into the local data structures */
+ status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table),
+ ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL,
+ TRUE, TRUE, &table_index);
- status = acpi_tb_add_table(&table_desc, &table_index);
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
if (ACPI_FAILURE(status)) {
/* Delete allocated table buffer */
- acpi_tb_delete_table(&table_desc);
+ ACPI_FREE(table);
+ return_ACPI_STATUS(status);
+ }
+
+ /*
+ * Note: Now table is "INSTALLED", it must be validated before
+ * loading.
+ */
+ status =
+ acpi_tb_validate_table(&acpi_gbl_root_table_list.
+ tables[table_index]);
+ if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
@@ -536,9 +535,6 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
return_ACPI_STATUS(status);
}
- ACPI_INFO((AE_INFO, "Dynamic OEM Table Load:"));
- acpi_tb_print_table_header(0, table_desc.pointer);
-
/* Remove the reference by added by acpi_ex_store above */
acpi_ut_remove_reference(ddb_handle);
@@ -546,8 +542,7 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
/* Invoke table handler if present */
if (acpi_gbl_table_handler) {
- (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD,
- table_desc.pointer,
+ (void)acpi_gbl_table_handler(ACPI_TABLE_EVENT_LOAD, table,
acpi_gbl_table_handler_context);
}
@@ -576,6 +571,13 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
ACPI_FUNCTION_TRACE(ex_unload_table);
/*
+ * Temporarily emit a warning so that the ASL for the machine can be
+ * hopefully obtained. This is to say that the Unload() operator is
+ * extremely rare if not completely unused.
+ */
+ ACPI_WARNING((AE_INFO, "Received request to unload an ACPI table"));
+
+ /*
* Validate the handle
* Although the handle is partially validated in acpi_ex_reconfiguration()
* when it calls acpi_ex_resolve_operands(), the handle is more completely
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c
index 973fdae00f94..925202acc3e4 100644
--- a/drivers/acpi/acpica/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -134,9 +134,11 @@ static struct acpi_exdump_info acpi_ex_dump_method[9] = {
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(method.aml_start), "Aml Start"}
};
-static struct acpi_exdump_info acpi_ex_dump_mutex[5] = {
+static struct acpi_exdump_info acpi_ex_dump_mutex[6] = {
{ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_mutex), NULL},
{ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.sync_level), "Sync Level"},
+ {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(mutex.original_sync_level),
+ "Original Sync Level"},
{ACPI_EXD_POINTER, ACPI_EXD_OFFSET(mutex.owner_thread), "Owner Thread"},
{ACPI_EXD_UINT16, ACPI_EXD_OFFSET(mutex.acquisition_depth),
"Acquire Depth"},
diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c
index e701d8c33dbf..6aade8e1d2a1 100644
--- a/drivers/acpi/acpica/hwpci.c
+++ b/drivers/acpi/acpica/hwpci.c
@@ -140,11 +140,12 @@ acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
/* Walk the list, updating the PCI device/function/bus numbers */
status = acpi_hw_process_pci_list(pci_id, list_head);
- }
- /* Always delete the list */
+ /* Delete the list */
+
+ acpi_hw_delete_pci_list(list_head);
+ }
- acpi_hw_delete_pci_list(list_head);
return_ACPI_STATUS(status);
}
@@ -187,6 +188,10 @@ acpi_hw_build_pci_list(acpi_handle root_pci_device,
while (1) {
status = acpi_get_parent(current_device, &parent_device);
if (ACPI_FAILURE(status)) {
+
+ /* Must delete the list before exit */
+
+ acpi_hw_delete_pci_list(*return_list_head);
return (status);
}
@@ -199,6 +204,10 @@ acpi_hw_build_pci_list(acpi_handle root_pci_device,
list_element = ACPI_ALLOCATE(sizeof(struct acpi_pci_device));
if (!list_element) {
+
+ /* Must delete the list before exit */
+
+ acpi_hw_delete_pci_list(*return_list_head);
return (AE_NO_MEMORY);
}
diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c
index 75d369050657..049d9c22a0f9 100644
--- a/drivers/acpi/acpica/rscreate.c
+++ b/drivers/acpi/acpica/rscreate.c
@@ -72,6 +72,8 @@ acpi_buffer_to_resource(u8 *aml_buffer,
void *resource;
void *current_resource_ptr;
+ ACPI_FUNCTION_TRACE(acpi_buffer_to_resource);
+
/*
* Note: we allow AE_AML_NO_RESOURCE_END_TAG, since an end tag
* is not required here.
@@ -85,7 +87,7 @@ acpi_buffer_to_resource(u8 *aml_buffer,
status = AE_OK;
}
if (ACPI_FAILURE(status)) {
- return (status);
+ return_ACPI_STATUS(status);
}
/* Allocate a buffer for the converted resource */
@@ -93,7 +95,7 @@ acpi_buffer_to_resource(u8 *aml_buffer,
resource = ACPI_ALLOCATE_ZEROED(list_size_needed);
current_resource_ptr = resource;
if (!resource) {
- return (AE_NO_MEMORY);
+ return_ACPI_STATUS(AE_NO_MEMORY);
}
/* Perform the AML-to-Resource conversion */
@@ -110,9 +112,11 @@ acpi_buffer_to_resource(u8 *aml_buffer,
*resource_ptr = resource;
}
- return (status);
+ return_ACPI_STATUS(status);
}
+ACPI_EXPORT_SYMBOL(acpi_buffer_to_resource)
+
/*******************************************************************************
*
* FUNCTION: acpi_rs_create_resource_list
@@ -130,10 +134,9 @@ acpi_buffer_to_resource(u8 *aml_buffer,
* of device resources.
*
******************************************************************************/
-
acpi_status
acpi_rs_create_resource_list(union acpi_operand_object *aml_buffer,
- struct acpi_buffer * output_buffer)
+ struct acpi_buffer *output_buffer)
{
acpi_status status;
diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c
new file mode 100644
index 000000000000..f499c10ceb4a
--- /dev/null
+++ b/drivers/acpi/acpica/tbdata.c
@@ -0,0 +1,760 @@
+/******************************************************************************
+ *
+ * Module Name: tbdata - Table manager data structure functions
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2014, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include "accommon.h"
+#include "acnamesp.h"
+#include "actables.h"
+
+#define _COMPONENT ACPI_TABLES
+ACPI_MODULE_NAME("tbdata")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_init_table_descriptor
+ *
+ * PARAMETERS: table_desc - Table descriptor
+ * address - Physical address of the table
+ * flags - Allocation flags of the table
+ * table - Pointer to the table
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Initialize a new table descriptor
+ *
+ ******************************************************************************/
+void
+acpi_tb_init_table_descriptor(struct acpi_table_desc *table_desc,
+ acpi_physical_address address,
+ u8 flags, struct acpi_table_header *table)
+{
+
+ /*
+ * Initialize the table descriptor. Set the pointer to NULL, since the
+ * table is not fully mapped at this time.
+ */
+ ACPI_MEMSET(table_desc, 0, sizeof(struct acpi_table_desc));
+ table_desc->address = address;
+ table_desc->length = table->length;
+ table_desc->flags = flags;
+ ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_acquire_table
+ *
+ * PARAMETERS: table_desc - Table descriptor
+ * table_ptr - Where table is returned
+ * table_length - Where table length is returned
+ * table_flags - Where table allocation flags are returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Acquire an ACPI table. It can be used for tables not
+ * maintained in the acpi_gbl_root_table_list.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_acquire_table(struct acpi_table_desc *table_desc,
+ struct acpi_table_header **table_ptr,
+ u32 *table_length, u8 *table_flags)
+{
+ struct acpi_table_header *table = NULL;
+
+ switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
+ case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL:
+
+ table =
+ acpi_os_map_memory(table_desc->address, table_desc->length);
+ break;
+
+ case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
+ case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:
+
+ table =
+ ACPI_CAST_PTR(struct acpi_table_header,
+ table_desc->address);
+ break;
+
+ default:
+
+ break;
+ }
+
+ /* Table is not valid yet */
+
+ if (!table) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Fill the return values */
+
+ *table_ptr = table;
+ *table_length = table_desc->length;
+ *table_flags = table_desc->flags;
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_release_table
+ *
+ * PARAMETERS: table - Pointer for the table
+ * table_length - Length for the table
+ * table_flags - Allocation flags for the table
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Release a table. The inverse of acpi_tb_acquire_table().
+ *
+ ******************************************************************************/
+
+void
+acpi_tb_release_table(struct acpi_table_header *table,
+ u32 table_length, u8 table_flags)
+{
+
+ switch (table_flags & ACPI_TABLE_ORIGIN_MASK) {
+ case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL:
+
+ acpi_os_unmap_memory(table, table_length);
+ break;
+
+ case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
+ case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:
+ default:
+
+ break;
+ }
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_acquire_temp_table
+ *
+ * PARAMETERS: table_desc - Table descriptor to be acquired
+ * address - Address of the table
+ * flags - Allocation flags of the table
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function validates the table header to obtain the length
+ * of a table and fills the table descriptor to make its state as
+ * "INSTALLED". Such a table descriptor is only used for verified
+ * installation.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_acquire_temp_table(struct acpi_table_desc *table_desc,
+ acpi_physical_address address, u8 flags)
+{
+ struct acpi_table_header *table_header;
+
+ switch (flags & ACPI_TABLE_ORIGIN_MASK) {
+ case ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL:
+
+ /* Get the length of the full table from the header */
+
+ table_header =
+ acpi_os_map_memory(address,
+ sizeof(struct acpi_table_header));
+ if (!table_header) {
+ return (AE_NO_MEMORY);
+ }
+
+ acpi_tb_init_table_descriptor(table_desc, address, flags,
+ table_header);
+ acpi_os_unmap_memory(table_header,
+ sizeof(struct acpi_table_header));
+ return (AE_OK);
+
+ case ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL:
+ case ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL:
+
+ table_header = ACPI_CAST_PTR(struct acpi_table_header, address);
+ if (!table_header) {
+ return (AE_NO_MEMORY);
+ }
+
+ acpi_tb_init_table_descriptor(table_desc, address, flags,
+ table_header);
+ return (AE_OK);
+
+ default:
+
+ break;
+ }
+
+ /* Table is not valid yet */
+
+ return (AE_NO_MEMORY);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_release_temp_table
+ *
+ * PARAMETERS: table_desc - Table descriptor to be released
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: The inverse of acpi_tb_acquire_temp_table().
+ *
+ *****************************************************************************/
+
+void acpi_tb_release_temp_table(struct acpi_table_desc *table_desc)
+{
+
+ /*
+ * Note that the .Address is maintained by the callers of
+ * acpi_tb_acquire_temp_table(), thus do not invoke acpi_tb_uninstall_table()
+ * where .Address will be freed.
+ */
+ acpi_tb_invalidate_table(table_desc);
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_tb_validate_table
+ *
+ * PARAMETERS: table_desc - Table descriptor
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to validate the table, the returned
+ * table descriptor is in "VALIDATED" state.
+ *
+ *****************************************************************************/
+
+acpi_status acpi_tb_validate_table(struct acpi_table_desc *table_desc)
+{
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE(tb_validate_table);
+
+ /* Validate the table if necessary */
+
+ if (!table_desc->pointer) {
+ status = acpi_tb_acquire_table(table_desc, &table_desc->pointer,
+ &table_desc->length,
+ &table_desc->flags);
+ if (!table_desc->pointer) {
+ status = AE_NO_MEMORY;
+ }
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_invalidate_table
+ *
+ * PARAMETERS: table_desc - Table descriptor
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Invalidate one internal ACPI table, this is the inverse of
+ * acpi_tb_validate_table().
+ *
+ ******************************************************************************/
+
+void acpi_tb_invalidate_table(struct acpi_table_desc *table_desc)
+{
+
+ ACPI_FUNCTION_TRACE(tb_invalidate_table);
+
+ /* Table must be validated */
+
+ if (!table_desc->pointer) {
+ return_VOID;
+ }
+
+ acpi_tb_release_table(table_desc->pointer, table_desc->length,
+ table_desc->flags);
+ table_desc->pointer = NULL;
+
+ return_VOID;
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_tb_validate_temp_table
+ *
+ * PARAMETERS: table_desc - Table descriptor
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to validate the table, the returned
+ * table descriptor is in "VALIDATED" state.
+ *
+ *****************************************************************************/
+
+acpi_status acpi_tb_validate_temp_table(struct acpi_table_desc *table_desc)
+{
+
+ if (!table_desc->pointer && !acpi_gbl_verify_table_checksum) {
+ /*
+ * Only validates the header of the table.
+ * Note that Length contains the size of the mapping after invoking
+ * this work around, this value is required by
+ * acpi_tb_release_temp_table().
+ * We can do this because in acpi_init_table_descriptor(), the Length
+ * field of the installed descriptor is filled with the actual
+ * table length obtaining from the table header.
+ */
+ table_desc->length = sizeof(struct acpi_table_header);
+ }
+
+ return (acpi_tb_validate_table(table_desc));
+}
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_tb_verify_temp_table
+ *
+ * PARAMETERS: table_desc - Table descriptor
+ * signature - Table signature to verify
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to validate and verify the table, the
+ * returned table descriptor is in "VALIDATED" state.
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_tb_verify_temp_table(struct acpi_table_desc * table_desc, char *signature)
+{
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE(tb_verify_temp_table);
+
+ /* Validate the table */
+
+ status = acpi_tb_validate_temp_table(table_desc);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /* If a particular signature is expected (DSDT/FACS), it must match */
+
+ if (signature && !ACPI_COMPARE_NAME(&table_desc->signature, signature)) {
+ ACPI_BIOS_ERROR((AE_INFO,
+ "Invalid signature 0x%X for ACPI table, expected [%s]",
+ table_desc->signature.integer, signature));
+ status = AE_BAD_SIGNATURE;
+ goto invalidate_and_exit;
+ }
+
+ /* Verify the checksum */
+
+ if (acpi_gbl_verify_table_checksum) {
+ status =
+ acpi_tb_verify_checksum(table_desc->pointer,
+ table_desc->length);
+ if (ACPI_FAILURE(status)) {
+ ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY,
+ "%4.4s " ACPI_PRINTF_UINT
+ " Attempted table install failed",
+ acpi_ut_valid_acpi_name(table_desc->
+ signature.
+ ascii) ?
+ table_desc->signature.ascii : "????",
+ ACPI_FORMAT_TO_UINT(table_desc->
+ address)));
+ goto invalidate_and_exit;
+ }
+ }
+
+ return_ACPI_STATUS(AE_OK);
+
+invalidate_and_exit:
+ acpi_tb_invalidate_table(table_desc);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_resize_root_table_list
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Expand the size of global table array
+ *
+ ******************************************************************************/
+
+acpi_status acpi_tb_resize_root_table_list(void)
+{
+ struct acpi_table_desc *tables;
+ u32 table_count;
+
+ ACPI_FUNCTION_TRACE(tb_resize_root_table_list);
+
+ /* allow_resize flag is a parameter to acpi_initialize_tables */
+
+ if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) {
+ ACPI_ERROR((AE_INFO,
+ "Resize of Root Table Array is not allowed"));
+ return_ACPI_STATUS(AE_SUPPORT);
+ }
+
+ /* Increase the Table Array size */
+
+ if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+ table_count = acpi_gbl_root_table_list.max_table_count;
+ } else {
+ table_count = acpi_gbl_root_table_list.current_table_count;
+ }
+
+ tables = ACPI_ALLOCATE_ZEROED(((acpi_size) table_count +
+ ACPI_ROOT_TABLE_SIZE_INCREMENT) *
+ sizeof(struct acpi_table_desc));
+ if (!tables) {
+ ACPI_ERROR((AE_INFO,
+ "Could not allocate new root table array"));
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+
+ /* Copy and free the previous table array */
+
+ if (acpi_gbl_root_table_list.tables) {
+ ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables,
+ (acpi_size) table_count *
+ sizeof(struct acpi_table_desc));
+
+ if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+ ACPI_FREE(acpi_gbl_root_table_list.tables);
+ }
+ }
+
+ acpi_gbl_root_table_list.tables = tables;
+ acpi_gbl_root_table_list.max_table_count =
+ table_count + ACPI_ROOT_TABLE_SIZE_INCREMENT;
+ acpi_gbl_root_table_list.flags |= ACPI_ROOT_ORIGIN_ALLOCATED;
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_get_next_root_index
+ *
+ * PARAMETERS: table_index - Where table index is returned
+ *
+ * RETURN: Status and table index.
+ *
+ * DESCRIPTION: Allocate a new ACPI table entry to the global table list
+ *
+ ******************************************************************************/
+
+acpi_status acpi_tb_get_next_root_index(u32 *table_index)
+{
+ acpi_status status;
+
+ /* Ensure that there is room for the table in the Root Table List */
+
+ if (acpi_gbl_root_table_list.current_table_count >=
+ acpi_gbl_root_table_list.max_table_count) {
+ status = acpi_tb_resize_root_table_list();
+ if (ACPI_FAILURE(status)) {
+ return (status);
+ }
+ }
+
+ *table_index = acpi_gbl_root_table_list.current_table_count;
+ acpi_gbl_root_table_list.current_table_count++;
+ return (AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_terminate
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Delete all internal ACPI tables
+ *
+ ******************************************************************************/
+
+void acpi_tb_terminate(void)
+{
+ u32 i;
+
+ ACPI_FUNCTION_TRACE(tb_terminate);
+
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+ /* Delete the individual tables */
+
+ for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) {
+ acpi_tb_uninstall_table(&acpi_gbl_root_table_list.tables[i]);
+ }
+
+ /*
+ * Delete the root table array if allocated locally. Array cannot be
+ * mapped, so we don't need to check for that flag.
+ */
+ if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+ ACPI_FREE(acpi_gbl_root_table_list.tables);
+ }
+
+ acpi_gbl_root_table_list.tables = NULL;
+ acpi_gbl_root_table_list.flags = 0;
+ acpi_gbl_root_table_list.current_table_count = 0;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n"));
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_delete_namespace_by_owner
+ *
+ * PARAMETERS: table_index - Table index
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Delete all namespace objects created when this table was loaded.
+ *
+ ******************************************************************************/
+
+acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index)
+{
+ acpi_owner_id owner_id;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(tb_delete_namespace_by_owner);
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ if (table_index >= acpi_gbl_root_table_list.current_table_count) {
+
+ /* The table index does not exist */
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
+ /* Get the owner ID for this table, used to delete namespace nodes */
+
+ owner_id = acpi_gbl_root_table_list.tables[table_index].owner_id;
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+
+ /*
+ * Need to acquire the namespace writer lock to prevent interference
+ * with any concurrent namespace walks. The interpreter must be
+ * released during the deletion since the acquisition of the deletion
+ * lock may block, and also since the execution of a namespace walk
+ * must be allowed to use the interpreter.
+ */
+ (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
+ status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock);
+
+ acpi_ns_delete_namespace_by_owner(owner_id);
+ if (ACPI_FAILURE(status)) {
+ return_ACPI_STATUS(status);
+ }
+
+ acpi_ut_release_write_lock(&acpi_gbl_namespace_rw_lock);
+
+ status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_allocate_owner_id
+ *
+ * PARAMETERS: table_index - Table index
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Allocates owner_id in table_desc
+ *
+ ******************************************************************************/
+
+acpi_status acpi_tb_allocate_owner_id(u32 table_index)
+{
+ acpi_status status = AE_BAD_PARAMETER;
+
+ ACPI_FUNCTION_TRACE(tb_allocate_owner_id);
+
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.current_table_count) {
+ status =
+ acpi_ut_allocate_owner_id(&
+ (acpi_gbl_root_table_list.
+ tables[table_index].owner_id));
+ }
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_release_owner_id
+ *
+ * PARAMETERS: table_index - Table index
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Releases owner_id in table_desc
+ *
+ ******************************************************************************/
+
+acpi_status acpi_tb_release_owner_id(u32 table_index)
+{
+ acpi_status status = AE_BAD_PARAMETER;
+
+ ACPI_FUNCTION_TRACE(tb_release_owner_id);
+
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.current_table_count) {
+ acpi_ut_release_owner_id(&
+ (acpi_gbl_root_table_list.
+ tables[table_index].owner_id));
+ status = AE_OK;
+ }
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_get_owner_id
+ *
+ * PARAMETERS: table_index - Table index
+ * owner_id - Where the table owner_id is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: returns owner_id for the ACPI table
+ *
+ ******************************************************************************/
+
+acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id * owner_id)
+{
+ acpi_status status = AE_BAD_PARAMETER;
+
+ ACPI_FUNCTION_TRACE(tb_get_owner_id);
+
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.current_table_count) {
+ *owner_id =
+ acpi_gbl_root_table_list.tables[table_index].owner_id;
+ status = AE_OK;
+ }
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_is_table_loaded
+ *
+ * PARAMETERS: table_index - Index into the root table
+ *
+ * RETURN: Table Loaded Flag
+ *
+ ******************************************************************************/
+
+u8 acpi_tb_is_table_loaded(u32 table_index)
+{
+ u8 is_loaded = FALSE;
+
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.current_table_count) {
+ is_loaded = (u8)
+ (acpi_gbl_root_table_list.tables[table_index].flags &
+ ACPI_TABLE_IS_LOADED);
+ }
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return (is_loaded);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_set_table_loaded_flag
+ *
+ * PARAMETERS: table_index - Table index
+ * is_loaded - TRUE if table is loaded, FALSE otherwise
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE.
+ *
+ ******************************************************************************/
+
+void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded)
+{
+
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ if (table_index < acpi_gbl_root_table_list.current_table_count) {
+ if (is_loaded) {
+ acpi_gbl_root_table_list.tables[table_index].flags |=
+ ACPI_TABLE_IS_LOADED;
+ } else {
+ acpi_gbl_root_table_list.tables[table_index].flags &=
+ ~ACPI_TABLE_IS_LOADED;
+ }
+ }
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+}
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index ec14588254d4..41519a958083 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -52,7 +52,8 @@ ACPI_MODULE_NAME("tbfadt")
static void
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
u8 space_id,
- u8 byte_width, u64 address, char *register_name);
+ u8 byte_width,
+ u64 address, char *register_name, u8 flags);
static void acpi_tb_convert_fadt(void);
@@ -69,13 +70,14 @@ typedef struct acpi_fadt_info {
u16 address32;
u16 length;
u8 default_length;
- u8 type;
+ u8 flags;
} acpi_fadt_info;
#define ACPI_FADT_OPTIONAL 0
#define ACPI_FADT_REQUIRED 1
#define ACPI_FADT_SEPARATE_LENGTH 2
+#define ACPI_FADT_GPE_REGISTER 4
static struct acpi_fadt_info fadt_info_table[] = {
{"Pm1aEventBlock",
@@ -125,14 +127,14 @@ static struct acpi_fadt_info fadt_info_table[] = {
ACPI_FADT_OFFSET(gpe0_block),
ACPI_FADT_OFFSET(gpe0_block_length),
0,
- ACPI_FADT_SEPARATE_LENGTH},
+ ACPI_FADT_SEPARATE_LENGTH | ACPI_FADT_GPE_REGISTER},
{"Gpe1Block",
ACPI_FADT_OFFSET(xgpe1_block),
ACPI_FADT_OFFSET(gpe1_block),
ACPI_FADT_OFFSET(gpe1_block_length),
0,
- ACPI_FADT_SEPARATE_LENGTH}
+ ACPI_FADT_SEPARATE_LENGTH | ACPI_FADT_GPE_REGISTER}
};
#define ACPI_FADT_INFO_ENTRIES \
@@ -189,19 +191,29 @@ static struct acpi_fadt_pm_info fadt_pm_info_table[] = {
static void
acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
u8 space_id,
- u8 byte_width, u64 address, char *register_name)
+ u8 byte_width,
+ u64 address, char *register_name, u8 flags)
{
u8 bit_width;
- /* Bit width field in the GAS is only one byte long, 255 max */
-
+ /*
+ * Bit width field in the GAS is only one byte long, 255 max.
+ * Check for bit_width overflow in GAS.
+ */
bit_width = (u8)(byte_width * 8);
-
- if (byte_width > 31) { /* (31*8)=248 */
- ACPI_ERROR((AE_INFO,
- "%s - 32-bit FADT register is too long (%u bytes, %u bits) "
- "to convert to GAS struct - 255 bits max, truncating",
- register_name, byte_width, (byte_width * 8)));
+ if (byte_width > 31) { /* (31*8)=248, (32*8)=256 */
+ /*
+ * No error for GPE blocks, because we do not use the bit_width
+ * for GPEs, the legacy length (byte_width) is used instead to
+ * allow for a large number of GPEs.
+ */
+ if (!(flags & ACPI_FADT_GPE_REGISTER)) {
+ ACPI_ERROR((AE_INFO,
+ "%s - 32-bit FADT register is too long (%u bytes, %u bits) "
+ "to convert to GAS struct - 255 bits max, truncating",
+ register_name, byte_width,
+ (byte_width * 8)));
+ }
bit_width = 255;
}
@@ -332,15 +344,15 @@ void acpi_tb_parse_fadt(u32 table_index)
/* Obtain the DSDT and FACS tables via their addresses within the FADT */
- acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
- ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);
+ acpi_tb_install_fixed_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
+ ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);
/* If Hardware Reduced flag is set, there is no FACS */
if (!acpi_gbl_reduced_hardware) {
- acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.
- Xfacs, ACPI_SIG_FACS,
- ACPI_TABLE_INDEX_FACS);
+ acpi_tb_install_fixed_table((acpi_physical_address)
+ acpi_gbl_FADT.Xfacs, ACPI_SIG_FACS,
+ ACPI_TABLE_INDEX_FACS);
}
}
@@ -450,6 +462,7 @@ static void acpi_tb_convert_fadt(void)
struct acpi_generic_address *address64;
u32 address32;
u8 length;
+ u8 flags;
u32 i;
/*
@@ -515,6 +528,7 @@ static void acpi_tb_convert_fadt(void)
fadt_info_table[i].length);
name = fadt_info_table[i].name;
+ flags = fadt_info_table[i].flags;
/*
* Expand the ACPI 1.0 32-bit addresses to the ACPI 2.0 64-bit "X"
@@ -554,7 +568,7 @@ static void acpi_tb_convert_fadt(void)
[i].
length),
(u64)address32,
- name);
+ name, flags);
} else if (address64->address != (u64)address32) {
/* Address mismatch */
@@ -582,7 +596,8 @@ static void acpi_tb_convert_fadt(void)
length),
(u64)
address32,
- name);
+ name,
+ flags);
}
}
}
@@ -603,7 +618,7 @@ static void acpi_tb_convert_fadt(void)
address64->bit_width));
}
- if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) {
+ if (fadt_info_table[i].flags & ACPI_FADT_REQUIRED) {
/*
* Field is required (Pm1a_event, Pm1a_control).
* Both the address and length must be non-zero.
@@ -617,7 +632,7 @@ static void acpi_tb_convert_fadt(void)
address),
length));
}
- } else if (fadt_info_table[i].type & ACPI_FADT_SEPARATE_LENGTH) {
+ } else if (fadt_info_table[i].flags & ACPI_FADT_SEPARATE_LENGTH) {
/*
* Field is optional (Pm2_control, GPE0, GPE1) AND has its own
* length field. If present, both the address and length must
@@ -726,7 +741,7 @@ static void acpi_tb_setup_fadt_registers(void)
(fadt_pm_info_table[i].
register_num *
pm1_register_byte_width),
- "PmRegisters");
+ "PmRegisters", 0);
}
}
}
diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c
index c12003947bd5..cb947700206c 100644
--- a/drivers/acpi/acpica/tbfind.c
+++ b/drivers/acpi/acpica/tbfind.c
@@ -99,8 +99,8 @@ acpi_tb_find_table(char *signature,
/* Table is not currently mapped, map it */
status =
- acpi_tb_verify_table(&acpi_gbl_root_table_list.
- tables[i]);
+ acpi_tb_validate_table(&acpi_gbl_root_table_list.
+ tables[i]);
if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status);
}
diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c
index e3040947e9a0..755b90c40ddf 100644
--- a/drivers/acpi/acpica/tbinstal.c
+++ b/drivers/acpi/acpica/tbinstal.c
@@ -43,688 +43,483 @@
#include <acpi/acpi.h>
#include "accommon.h"
-#include "acnamesp.h"
#include "actables.h"
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME("tbinstal")
-/******************************************************************************
+/* Local prototypes */
+static u8
+acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index);
+
+/*******************************************************************************
*
- * FUNCTION: acpi_tb_verify_table
+ * FUNCTION: acpi_tb_compare_tables
*
- * PARAMETERS: table_desc - table
+ * PARAMETERS: table_desc - Table 1 descriptor to be compared
+ * table_index - Index of table 2 to be compared
*
- * RETURN: Status
+ * RETURN: TRUE if both tables are identical.
*
- * DESCRIPTION: this function is called to verify and map table
+ * DESCRIPTION: This function compares a table with another table that has
+ * already been installed in the root table list.
*
- *****************************************************************************/
-acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc)
+ ******************************************************************************/
+
+static u8
+acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index)
{
acpi_status status = AE_OK;
+ u8 is_identical;
+ struct acpi_table_header *table;
+ u32 table_length;
+ u8 table_flags;
- ACPI_FUNCTION_TRACE(tb_verify_table);
-
- /* Map the table if necessary */
-
- if (!table_desc->pointer) {
- if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) ==
- ACPI_TABLE_ORIGIN_MAPPED) {
- table_desc->pointer =
- acpi_os_map_memory(table_desc->address,
- table_desc->length);
- }
- if (!table_desc->pointer) {
- return_ACPI_STATUS(AE_NO_MEMORY);
- }
+ status =
+ acpi_tb_acquire_table(&acpi_gbl_root_table_list.tables[table_index],
+ &table, &table_length, &table_flags);
+ if (ACPI_FAILURE(status)) {
+ return (FALSE);
}
- /* Always calculate checksum, ignore bad checksum if requested */
+ /*
+ * Check for a table match on the entire table length,
+ * not just the header.
+ */
+ is_identical = (u8)((table_desc->length != table_length ||
+ ACPI_MEMCMP(table_desc->pointer, table,
+ table_length)) ? FALSE : TRUE);
- status =
- acpi_tb_verify_checksum(table_desc->pointer, table_desc->length);
+ /* Release the acquired table */
- return_ACPI_STATUS(status);
+ acpi_tb_release_table(table, table_length, table_flags);
+ return (is_identical);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_add_table
+ * FUNCTION: acpi_tb_install_table_with_override
*
- * PARAMETERS: table_desc - Table descriptor
- * table_index - Where the table index is returned
+ * PARAMETERS: table_index - Index into root table array
+ * new_table_desc - New table descriptor to install
+ * override - Whether override should be performed
*
- * RETURN: Status
+ * RETURN: None
*
- * DESCRIPTION: This function is called to add an ACPI table. It is used to
- * dynamically load tables via the Load and load_table AML
- * operators.
+ * DESCRIPTION: Install an ACPI table into the global data structure. The
+ * table override mechanism is called to allow the host
+ * OS to replace any table before it is installed in the root
+ * table array.
*
******************************************************************************/
-acpi_status
-acpi_tb_add_table(struct acpi_table_desc *table_desc, u32 *table_index)
+void
+acpi_tb_install_table_with_override(u32 table_index,
+ struct acpi_table_desc *new_table_desc,
+ u8 override)
{
- u32 i;
- acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE(tb_add_table);
-
- if (!table_desc->pointer) {
- status = acpi_tb_verify_table(table_desc);
- if (ACPI_FAILURE(status) || !table_desc->pointer) {
- return_ACPI_STATUS(status);
- }
+ if (table_index >= acpi_gbl_root_table_list.current_table_count) {
+ return;
}
/*
- * Validate the incoming table signature.
+ * ACPI Table Override:
*
- * 1) Originally, we checked the table signature for "SSDT" or "PSDT".
- * 2) We added support for OEMx tables, signature "OEM".
- * 3) Valid tables were encountered with a null signature, so we just
- * gave up on validating the signature, (05/2008).
- * 4) We encountered non-AML tables such as the MADT, which caused
- * interpreter errors and kernel faults. So now, we once again allow
- * only "SSDT", "OEMx", and now, also a null signature. (05/2011).
+ * Before we install the table, let the host OS override it with a new
+ * one if desired. Any table within the RSDT/XSDT can be replaced,
+ * including the DSDT which is pointed to by the FADT.
*/
- if ((table_desc->pointer->signature[0] != 0x00) &&
- (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT))
- && (ACPI_STRNCMP(table_desc->pointer->signature, "OEM", 3))) {
- ACPI_BIOS_ERROR((AE_INFO,
- "Table has invalid signature [%4.4s] (0x%8.8X), "
- "must be SSDT or OEMx",
- acpi_ut_valid_acpi_name(table_desc->pointer->
- signature) ?
- table_desc->pointer->signature : "????",
- *(u32 *)table_desc->pointer->signature));
-
- return_ACPI_STATUS(AE_BAD_SIGNATURE);
+ if (override) {
+ acpi_tb_override_table(new_table_desc);
}
- (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list.
+ tables[table_index],
+ new_table_desc->address,
+ new_table_desc->flags,
+ new_table_desc->pointer);
- /* Check if table is already registered */
+ acpi_tb_print_table_header(new_table_desc->address,
+ new_table_desc->pointer);
- for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) {
- if (!acpi_gbl_root_table_list.tables[i].pointer) {
- status =
- acpi_tb_verify_table(&acpi_gbl_root_table_list.
- tables[i]);
- if (ACPI_FAILURE(status)
- || !acpi_gbl_root_table_list.tables[i].pointer) {
- continue;
- }
- }
+ /* Set the global integer width (based upon revision of the DSDT) */
- /*
- * Check for a table match on the entire table length,
- * not just the header.
- */
- if (table_desc->length !=
- acpi_gbl_root_table_list.tables[i].length) {
- continue;
- }
-
- if (ACPI_MEMCMP(table_desc->pointer,
- acpi_gbl_root_table_list.tables[i].pointer,
- acpi_gbl_root_table_list.tables[i].length)) {
- continue;
- }
-
- /*
- * Note: the current mechanism does not unregister a table if it is
- * dynamically unloaded. The related namespace entries are deleted,
- * but the table remains in the root table list.
- *
- * The assumption here is that the number of different tables that
- * will be loaded is actually small, and there is minimal overhead
- * in just keeping the table in case it is needed again.
- *
- * If this assumption changes in the future (perhaps on large
- * machines with many table load/unload operations), tables will
- * need to be unregistered when they are unloaded, and slots in the
- * root table list should be reused when empty.
- */
-
- /*
- * Table is already registered.
- * We can delete the table that was passed as a parameter.
- */
- acpi_tb_delete_table(table_desc);
- *table_index = i;
-
- if (acpi_gbl_root_table_list.tables[i].
- flags & ACPI_TABLE_IS_LOADED) {
-
- /* Table is still loaded, this is an error */
-
- status = AE_ALREADY_EXISTS;
- goto release;
- } else {
- /* Table was unloaded, allow it to be reloaded */
-
- table_desc->pointer =
- acpi_gbl_root_table_list.tables[i].pointer;
- table_desc->address =
- acpi_gbl_root_table_list.tables[i].address;
- status = AE_OK;
- goto print_header;
- }
+ if (table_index == ACPI_TABLE_INDEX_DSDT) {
+ acpi_ut_set_integer_width(new_table_desc->pointer->revision);
}
-
- /*
- * ACPI Table Override:
- * Allow the host to override dynamically loaded tables.
- * NOTE: the table is fully mapped at this point, and the mapping will
- * be deleted by tb_table_override if the table is actually overridden.
- */
- (void)acpi_tb_table_override(table_desc->pointer, table_desc);
-
- /* Add the table to the global root table list */
-
- status = acpi_tb_store_table(table_desc->address, table_desc->pointer,
- table_desc->length, table_desc->flags,
- table_index);
- if (ACPI_FAILURE(status)) {
- goto release;
- }
-
-print_header:
- acpi_tb_print_table_header(table_desc->address, table_desc->pointer);
-
-release:
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- return_ACPI_STATUS(status);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_table_override
+ * FUNCTION: acpi_tb_install_fixed_table
*
- * PARAMETERS: table_header - Header for the original table
- * table_desc - Table descriptor initialized for the
- * original table. May or may not be mapped.
+ * PARAMETERS: address - Physical address of DSDT or FACS
+ * signature - Table signature, NULL if no need to
+ * match
+ * table_index - Index into root table array
*
- * RETURN: Pointer to the entire new table. NULL if table not overridden.
- * If overridden, installs the new table within the input table
- * descriptor.
+ * RETURN: Status
*
- * DESCRIPTION: Attempt table override by calling the OSL override functions.
- * Note: If the table is overridden, then the entire new table
- * is mapped and returned by this function.
+ * DESCRIPTION: Install a fixed ACPI table (DSDT/FACS) into the global data
+ * structure.
*
******************************************************************************/
-struct acpi_table_header *acpi_tb_table_override(struct acpi_table_header
- *table_header,
- struct acpi_table_desc
- *table_desc)
+acpi_status
+acpi_tb_install_fixed_table(acpi_physical_address address,
+ char *signature, u32 table_index)
{
+ struct acpi_table_desc new_table_desc;
acpi_status status;
- struct acpi_table_header *new_table = NULL;
- acpi_physical_address new_address = 0;
- u32 new_table_length = 0;
- u8 new_flags;
- char *override_type;
- /* (1) Attempt logical override (returns a logical address) */
+ ACPI_FUNCTION_TRACE(tb_install_fixed_table);
- status = acpi_os_table_override(table_header, &new_table);
- if (ACPI_SUCCESS(status) && new_table) {
- new_address = ACPI_PTR_TO_PHYSADDR(new_table);
- new_table_length = new_table->length;
- new_flags = ACPI_TABLE_ORIGIN_OVERRIDE;
- override_type = "Logical";
- goto finish_override;
+ if (!address) {
+ ACPI_ERROR((AE_INFO,
+ "Null physical address for ACPI table [%s]",
+ signature));
+ return (AE_NO_MEMORY);
}
- /* (2) Attempt physical override (returns a physical address) */
+ /* Fill a table descriptor for validation */
- status = acpi_os_physical_table_override(table_header,
- &new_address,
- &new_table_length);
- if (ACPI_SUCCESS(status) && new_address && new_table_length) {
-
- /* Map the entire new table */
-
- new_table = acpi_os_map_memory(new_address, new_table_length);
- if (!new_table) {
- ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY,
- "%4.4s " ACPI_PRINTF_UINT
- " Attempted physical table override failed",
- table_header->signature,
- ACPI_FORMAT_TO_UINT(table_desc->
- address)));
- return (NULL);
- }
-
- override_type = "Physical";
- new_flags = ACPI_TABLE_ORIGIN_MAPPED;
- goto finish_override;
+ status = acpi_tb_acquire_temp_table(&new_table_desc, address,
+ ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO, "Could not acquire table length at %p",
+ ACPI_CAST_PTR(void, address)));
+ return_ACPI_STATUS(status);
}
- return (NULL); /* There was no override */
-
-finish_override:
-
- ACPI_INFO((AE_INFO, "%4.4s " ACPI_PRINTF_UINT
- " %s table override, new table: " ACPI_PRINTF_UINT,
- table_header->signature,
- ACPI_FORMAT_TO_UINT(table_desc->address),
- override_type, ACPI_FORMAT_TO_UINT(new_table)));
+ /* Validate and verify a table before installation */
- /* We can now unmap/delete the original table (if fully mapped) */
+ status = acpi_tb_verify_temp_table(&new_table_desc, signature);
+ if (ACPI_FAILURE(status)) {
+ goto release_and_exit;
+ }
- acpi_tb_delete_table(table_desc);
+ acpi_tb_install_table_with_override(table_index, &new_table_desc, TRUE);
- /* Setup descriptor for the new table */
+release_and_exit:
- table_desc->address = new_address;
- table_desc->pointer = new_table;
- table_desc->length = new_table_length;
- table_desc->flags = new_flags;
+ /* Release the temporary table descriptor */
- return (new_table);
+ acpi_tb_release_temp_table(&new_table_desc);
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_resize_root_table_list
+ * FUNCTION: acpi_tb_install_standard_table
*
- * PARAMETERS: None
+ * PARAMETERS: address - Address of the table (might be a virtual
+ * address depending on the table_flags)
+ * flags - Flags for the table
+ * reload - Whether reload should be performed
+ * override - Whether override should be performed
+ * table_index - Where the table index is returned
*
* RETURN: Status
*
- * DESCRIPTION: Expand the size of global table array
+ * DESCRIPTION: This function is called to install an ACPI table that is
+ * neither DSDT nor FACS (a "standard" table.)
+ * When this function is called by "Load" or "LoadTable" opcodes,
+ * or by acpi_load_table() API, the "Reload" parameter is set.
+ * After sucessfully returning from this function, table is
+ * "INSTALLED" but not "VALIDATED".
*
******************************************************************************/
-acpi_status acpi_tb_resize_root_table_list(void)
+acpi_status
+acpi_tb_install_standard_table(acpi_physical_address address,
+ u8 flags,
+ u8 reload, u8 override, u32 *table_index)
{
- struct acpi_table_desc *tables;
- u32 table_count;
-
- ACPI_FUNCTION_TRACE(tb_resize_root_table_list);
-
- /* allow_resize flag is a parameter to acpi_initialize_tables */
+ u32 i;
+ acpi_status status = AE_OK;
+ struct acpi_table_desc new_table_desc;
- if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) {
- ACPI_ERROR((AE_INFO,
- "Resize of Root Table Array is not allowed"));
- return_ACPI_STATUS(AE_SUPPORT);
- }
+ ACPI_FUNCTION_TRACE(tb_install_standard_table);
- /* Increase the Table Array size */
+ /* Acquire a temporary table descriptor for validation */
- if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
- table_count = acpi_gbl_root_table_list.max_table_count;
- } else {
- table_count = acpi_gbl_root_table_list.current_table_count;
+ status = acpi_tb_acquire_temp_table(&new_table_desc, address, flags);
+ if (ACPI_FAILURE(status)) {
+ ACPI_ERROR((AE_INFO, "Could not acquire table length at %p",
+ ACPI_CAST_PTR(void, address)));
+ return_ACPI_STATUS(status);
}
- tables = ACPI_ALLOCATE_ZEROED(((acpi_size) table_count +
- ACPI_ROOT_TABLE_SIZE_INCREMENT) *
- sizeof(struct acpi_table_desc));
- if (!tables) {
- ACPI_ERROR((AE_INFO,
- "Could not allocate new root table array"));
- return_ACPI_STATUS(AE_NO_MEMORY);
+ /*
+ * Optionally do not load any SSDTs from the RSDT/XSDT. This can
+ * be useful for debugging ACPI problems on some machines.
+ */
+ if (!reload &&
+ acpi_gbl_disable_ssdt_table_install &&
+ ACPI_COMPARE_NAME(&new_table_desc.signature, ACPI_SIG_SSDT)) {
+ ACPI_INFO((AE_INFO, "Ignoring installation of %4.4s at %p",
+ new_table_desc.signature.ascii, ACPI_CAST_PTR(void,
+ address)));
+ goto release_and_exit;
}
- /* Copy and free the previous table array */
-
- if (acpi_gbl_root_table_list.tables) {
- ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables,
- (acpi_size) table_count *
- sizeof(struct acpi_table_desc));
+ /* Validate and verify a table before installation */
- if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
- ACPI_FREE(acpi_gbl_root_table_list.tables);
- }
+ status = acpi_tb_verify_temp_table(&new_table_desc, NULL);
+ if (ACPI_FAILURE(status)) {
+ goto release_and_exit;
}
- acpi_gbl_root_table_list.tables = tables;
- acpi_gbl_root_table_list.max_table_count =
- table_count + ACPI_ROOT_TABLE_SIZE_INCREMENT;
- acpi_gbl_root_table_list.flags |= ACPI_ROOT_ORIGIN_ALLOCATED;
-
- return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_store_table
- *
- * PARAMETERS: address - Table address
- * table - Table header
- * length - Table length
- * flags - flags
- *
- * RETURN: Status and table index.
- *
- * DESCRIPTION: Add an ACPI table to the global table list
- *
- ******************************************************************************/
+ if (reload) {
+ /*
+ * Validate the incoming table signature.
+ *
+ * 1) Originally, we checked the table signature for "SSDT" or "PSDT".
+ * 2) We added support for OEMx tables, signature "OEM".
+ * 3) Valid tables were encountered with a null signature, so we just
+ * gave up on validating the signature, (05/2008).
+ * 4) We encountered non-AML tables such as the MADT, which caused
+ * interpreter errors and kernel faults. So now, we once again allow
+ * only "SSDT", "OEMx", and now, also a null signature. (05/2011).
+ */
+ if ((new_table_desc.signature.ascii[0] != 0x00) &&
+ (!ACPI_COMPARE_NAME
+ (&new_table_desc.signature, ACPI_SIG_SSDT))
+ && (ACPI_STRNCMP(new_table_desc.signature.ascii, "OEM", 3)))
+ {
+ ACPI_BIOS_ERROR((AE_INFO,
+ "Table has invalid signature [%4.4s] (0x%8.8X), "
+ "must be SSDT or OEMx",
+ acpi_ut_valid_acpi_name(new_table_desc.
+ signature.
+ ascii) ?
+ new_table_desc.signature.
+ ascii : "????",
+ new_table_desc.signature.integer));
+
+ status = AE_BAD_SIGNATURE;
+ goto release_and_exit;
+ }
-acpi_status
-acpi_tb_store_table(acpi_physical_address address,
- struct acpi_table_header *table,
- u32 length, u8 flags, u32 *table_index)
-{
- acpi_status status;
- struct acpi_table_desc *new_table;
+ /* Check if table is already registered */
- /* Ensure that there is room for the table in the Root Table List */
+ for (i = 0; i < acpi_gbl_root_table_list.current_table_count;
+ ++i) {
+ /*
+ * Check for a table match on the entire table length,
+ * not just the header.
+ */
+ if (!acpi_tb_compare_tables(&new_table_desc, i)) {
+ continue;
+ }
- if (acpi_gbl_root_table_list.current_table_count >=
- acpi_gbl_root_table_list.max_table_count) {
- status = acpi_tb_resize_root_table_list();
- if (ACPI_FAILURE(status)) {
- return (status);
+ /*
+ * Note: the current mechanism does not unregister a table if it is
+ * dynamically unloaded. The related namespace entries are deleted,
+ * but the table remains in the root table list.
+ *
+ * The assumption here is that the number of different tables that
+ * will be loaded is actually small, and there is minimal overhead
+ * in just keeping the table in case it is needed again.
+ *
+ * If this assumption changes in the future (perhaps on large
+ * machines with many table load/unload operations), tables will
+ * need to be unregistered when they are unloaded, and slots in the
+ * root table list should be reused when empty.
+ */
+ if (acpi_gbl_root_table_list.tables[i].
+ flags & ACPI_TABLE_IS_LOADED) {
+
+ /* Table is still loaded, this is an error */
+
+ status = AE_ALREADY_EXISTS;
+ goto release_and_exit;
+ } else {
+ /*
+ * Table was unloaded, allow it to be reloaded.
+ * As we are going to return AE_OK to the caller, we should
+ * take the responsibility of freeing the input descriptor.
+ * Refill the input descriptor to ensure
+ * acpi_tb_install_table_with_override() can be called again to
+ * indicate the re-installation.
+ */
+ acpi_tb_uninstall_table(&new_table_desc);
+ *table_index = i;
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ return_ACPI_STATUS(AE_OK);
+ }
}
}
- new_table =
- &acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.
- current_table_count];
-
- /* Initialize added table */
-
- new_table->address = address;
- new_table->pointer = table;
- new_table->length = length;
- new_table->owner_id = 0;
- new_table->flags = flags;
-
- ACPI_MOVE_32_TO_32(&new_table->signature, table->signature);
-
- *table_index = acpi_gbl_root_table_list.current_table_count;
- acpi_gbl_root_table_list.current_table_count++;
- return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_delete_table
- *
- * PARAMETERS: table_index - Table index
- *
- * RETURN: None
- *
- * DESCRIPTION: Delete one internal ACPI table
- *
- ******************************************************************************/
+ /* Add the table to the global root table list */
-void acpi_tb_delete_table(struct acpi_table_desc *table_desc)
-{
- /* Table must be mapped or allocated */
- if (!table_desc->pointer) {
- return;
+ status = acpi_tb_get_next_root_index(&i);
+ if (ACPI_FAILURE(status)) {
+ goto release_and_exit;
}
- switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
- case ACPI_TABLE_ORIGIN_MAPPED:
-
- acpi_os_unmap_memory(table_desc->pointer, table_desc->length);
- break;
-
- case ACPI_TABLE_ORIGIN_ALLOCATED:
- ACPI_FREE(table_desc->pointer);
- break;
+ *table_index = i;
+ acpi_tb_install_table_with_override(i, &new_table_desc, override);
- /* Not mapped or allocated, there is nothing we can do */
+release_and_exit:
- default:
+ /* Release the temporary table descriptor */
- return;
- }
-
- table_desc->pointer = NULL;
+ acpi_tb_release_temp_table(&new_table_desc);
+ return_ACPI_STATUS(status);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_terminate
+ * FUNCTION: acpi_tb_override_table
*
- * PARAMETERS: None
+ * PARAMETERS: old_table_desc - Validated table descriptor to be
+ * overridden
*
* RETURN: None
*
- * DESCRIPTION: Delete all internal ACPI tables
+ * DESCRIPTION: Attempt table override by calling the OSL override functions.
+ * Note: If the table is overridden, then the entire new table
+ * is acquired and returned by this function.
+ * Before/after invocation, the table descriptor is in a state
+ * that is "VALIDATED".
*
******************************************************************************/
-void acpi_tb_terminate(void)
+void acpi_tb_override_table(struct acpi_table_desc *old_table_desc)
{
- u32 i;
-
- ACPI_FUNCTION_TRACE(tb_terminate);
-
- (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
-
- /* Delete the individual tables */
+ acpi_status status;
+ char *override_type;
+ struct acpi_table_desc new_table_desc;
+ struct acpi_table_header *table;
+ acpi_physical_address address;
+ u32 length;
- for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) {
- acpi_tb_delete_table(&acpi_gbl_root_table_list.tables[i]);
- }
+ /* (1) Attempt logical override (returns a logical address) */
- /*
- * Delete the root table array if allocated locally. Array cannot be
- * mapped, so we don't need to check for that flag.
- */
- if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
- ACPI_FREE(acpi_gbl_root_table_list.tables);
+ status = acpi_os_table_override(old_table_desc->pointer, &table);
+ if (ACPI_SUCCESS(status) && table) {
+ acpi_tb_acquire_temp_table(&new_table_desc,
+ ACPI_PTR_TO_PHYSADDR(table),
+ ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL);
+ override_type = "Logical";
+ goto finish_override;
}
- acpi_gbl_root_table_list.tables = NULL;
- acpi_gbl_root_table_list.flags = 0;
- acpi_gbl_root_table_list.current_table_count = 0;
+ /* (2) Attempt physical override (returns a physical address) */
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n"));
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ status = acpi_os_physical_table_override(old_table_desc->pointer,
+ &address, &length);
+ if (ACPI_SUCCESS(status) && address && length) {
+ acpi_tb_acquire_temp_table(&new_table_desc, address,
+ ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL);
+ override_type = "Physical";
+ goto finish_override;
+ }
- return_VOID;
-}
+ return; /* There was no override */
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_delete_namespace_by_owner
- *
- * PARAMETERS: table_index - Table index
- *
- * RETURN: Status
- *
- * DESCRIPTION: Delete all namespace objects created when this table was loaded.
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_delete_namespace_by_owner(u32 table_index)
-{
- acpi_owner_id owner_id;
- acpi_status status;
+finish_override:
- ACPI_FUNCTION_TRACE(tb_delete_namespace_by_owner);
+ /* Validate and verify a table before overriding */
- status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+ status = acpi_tb_verify_temp_table(&new_table_desc, NULL);
if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
+ return;
}
- if (table_index >= acpi_gbl_root_table_list.current_table_count) {
-
- /* The table index does not exist */
-
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- return_ACPI_STATUS(AE_NOT_EXIST);
- }
+ ACPI_INFO((AE_INFO, "%4.4s " ACPI_PRINTF_UINT
+ " %s table override, new table: " ACPI_PRINTF_UINT,
+ old_table_desc->signature.ascii,
+ ACPI_FORMAT_TO_UINT(old_table_desc->address),
+ override_type, ACPI_FORMAT_TO_UINT(new_table_desc.address)));
- /* Get the owner ID for this table, used to delete namespace nodes */
+ /* We can now uninstall the original table */
- owner_id = acpi_gbl_root_table_list.tables[table_index].owner_id;
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ acpi_tb_uninstall_table(old_table_desc);
/*
- * Need to acquire the namespace writer lock to prevent interference
- * with any concurrent namespace walks. The interpreter must be
- * released during the deletion since the acquisition of the deletion
- * lock may block, and also since the execution of a namespace walk
- * must be allowed to use the interpreter.
+ * Replace the original table descriptor and keep its state as
+ * "VALIDATED".
*/
- (void)acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
- status = acpi_ut_acquire_write_lock(&acpi_gbl_namespace_rw_lock);
+ acpi_tb_init_table_descriptor(old_table_desc, new_table_desc.address,
+ new_table_desc.flags,
+ new_table_desc.pointer);
+ acpi_tb_validate_temp_table(old_table_desc);
- acpi_ns_delete_namespace_by_owner(owner_id);
- if (ACPI_FAILURE(status)) {
- return_ACPI_STATUS(status);
- }
+ /* Release the temporary table descriptor */
- acpi_ut_release_write_lock(&acpi_gbl_namespace_rw_lock);
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
- return_ACPI_STATUS(status);
+ acpi_tb_release_temp_table(&new_table_desc);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_allocate_owner_id
+ * FUNCTION: acpi_tb_store_table
*
- * PARAMETERS: table_index - Table index
+ * PARAMETERS: address - Table address
+ * table - Table header
+ * length - Table length
+ * flags - Install flags
+ * table_index - Where the table index is returned
*
- * RETURN: Status
+ * RETURN: Status and table index.
*
- * DESCRIPTION: Allocates owner_id in table_desc
+ * DESCRIPTION: Add an ACPI table to the global table list
*
******************************************************************************/
-acpi_status acpi_tb_allocate_owner_id(u32 table_index)
+acpi_status
+acpi_tb_store_table(acpi_physical_address address,
+ struct acpi_table_header * table,
+ u32 length, u8 flags, u32 *table_index)
{
- acpi_status status = AE_BAD_PARAMETER;
-
- ACPI_FUNCTION_TRACE(tb_allocate_owner_id);
+ acpi_status status;
+ struct acpi_table_desc *table_desc;
- (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if (table_index < acpi_gbl_root_table_list.current_table_count) {
- status = acpi_ut_allocate_owner_id
- (&(acpi_gbl_root_table_list.tables[table_index].owner_id));
+ status = acpi_tb_get_next_root_index(table_index);
+ if (ACPI_FAILURE(status)) {
+ return (status);
}
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_release_owner_id
- *
- * PARAMETERS: table_index - Table index
- *
- * RETURN: Status
- *
- * DESCRIPTION: Releases owner_id in table_desc
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_release_owner_id(u32 table_index)
-{
- acpi_status status = AE_BAD_PARAMETER;
-
- ACPI_FUNCTION_TRACE(tb_release_owner_id);
-
- (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if (table_index < acpi_gbl_root_table_list.current_table_count) {
- acpi_ut_release_owner_id(&
- (acpi_gbl_root_table_list.
- tables[table_index].owner_id));
- status = AE_OK;
- }
+ /* Initialize added table */
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- return_ACPI_STATUS(status);
+ table_desc = &acpi_gbl_root_table_list.tables[*table_index];
+ acpi_tb_init_table_descriptor(table_desc, address, flags, table);
+ table_desc->pointer = table;
+ return (AE_OK);
}
/*******************************************************************************
*
- * FUNCTION: acpi_tb_get_owner_id
+ * FUNCTION: acpi_tb_uninstall_table
*
- * PARAMETERS: table_index - Table index
- * owner_id - Where the table owner_id is returned
+ * PARAMETERS: table_desc - Table descriptor
*
- * RETURN: Status
+ * RETURN: None
*
- * DESCRIPTION: returns owner_id for the ACPI table
+ * DESCRIPTION: Delete one internal ACPI table
*
******************************************************************************/
-acpi_status acpi_tb_get_owner_id(u32 table_index, acpi_owner_id *owner_id)
+void acpi_tb_uninstall_table(struct acpi_table_desc *table_desc)
{
- acpi_status status = AE_BAD_PARAMETER;
-
- ACPI_FUNCTION_TRACE(tb_get_owner_id);
- (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if (table_index < acpi_gbl_root_table_list.current_table_count) {
- *owner_id =
- acpi_gbl_root_table_list.tables[table_index].owner_id;
- status = AE_OK;
- }
+ ACPI_FUNCTION_TRACE(tb_uninstall_table);
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_is_table_loaded
- *
- * PARAMETERS: table_index - Table index
- *
- * RETURN: Table Loaded Flag
- *
- ******************************************************************************/
+ /* Table must be installed */
-u8 acpi_tb_is_table_loaded(u32 table_index)
-{
- u8 is_loaded = FALSE;
-
- (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if (table_index < acpi_gbl_root_table_list.current_table_count) {
- is_loaded = (u8)
- (acpi_gbl_root_table_list.tables[table_index].flags &
- ACPI_TABLE_IS_LOADED);
+ if (!table_desc->address) {
+ return_VOID;
}
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
- return (is_loaded);
-}
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_set_table_loaded_flag
- *
- * PARAMETERS: table_index - Table index
- * is_loaded - TRUE if table is loaded, FALSE otherwise
- *
- * RETURN: None
- *
- * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE.
- *
- ******************************************************************************/
-
-void acpi_tb_set_table_loaded_flag(u32 table_index, u8 is_loaded)
-{
+ acpi_tb_invalidate_table(table_desc);
- (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
- if (table_index < acpi_gbl_root_table_list.current_table_count) {
- if (is_loaded) {
- acpi_gbl_root_table_list.tables[table_index].flags |=
- ACPI_TABLE_IS_LOADED;
- } else {
- acpi_gbl_root_table_list.tables[table_index].flags &=
- ~ACPI_TABLE_IS_LOADED;
- }
+ if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) ==
+ ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL) {
+ ACPI_FREE(ACPI_CAST_PTR(void, table_desc->address));
}
- (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ table_desc->address = ACPI_PTR_TO_PHYSADDR(NULL);
+ return_VOID;
}
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 9fb85f38de90..6b1ca9991b90 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -49,8 +49,6 @@
ACPI_MODULE_NAME("tbutils")
/* Local prototypes */
-static acpi_status acpi_tb_validate_xsdt(acpi_physical_address address);
-
static acpi_physical_address
acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
@@ -178,9 +176,13 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index)
}
ACPI_MEMCPY(new_table, table_desc->pointer, table_desc->length);
- acpi_tb_delete_table(table_desc);
- table_desc->pointer = new_table;
- table_desc->flags = ACPI_TABLE_ORIGIN_ALLOCATED;
+ acpi_tb_uninstall_table(table_desc);
+
+ acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list.
+ tables[ACPI_TABLE_INDEX_DSDT],
+ ACPI_PTR_TO_PHYSADDR(new_table),
+ ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL,
+ new_table);
ACPI_INFO((AE_INFO,
"Forced DSDT copy: length 0x%05X copied locally, original unmapped",
@@ -191,116 +193,6 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index)
/*******************************************************************************
*
- * FUNCTION: acpi_tb_install_table
- *
- * PARAMETERS: address - Physical address of DSDT or FACS
- * signature - Table signature, NULL if no need to
- * match
- * table_index - Index into root table array
- *
- * RETURN: None
- *
- * DESCRIPTION: Install an ACPI table into the global data structure. The
- * table override mechanism is called to allow the host
- * OS to replace any table before it is installed in the root
- * table array.
- *
- ******************************************************************************/
-
-void
-acpi_tb_install_table(acpi_physical_address address,
- char *signature, u32 table_index)
-{
- struct acpi_table_header *table;
- struct acpi_table_header *final_table;
- struct acpi_table_desc *table_desc;
-
- if (!address) {
- ACPI_ERROR((AE_INFO,
- "Null physical address for ACPI table [%s]",
- signature));
- return;
- }
-
- /* Map just the table header */
-
- table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
- if (!table) {
- ACPI_ERROR((AE_INFO,
- "Could not map memory for table [%s] at %p",
- signature, ACPI_CAST_PTR(void, address)));
- return;
- }
-
- /* If a particular signature is expected (DSDT/FACS), it must match */
-
- if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) {
- ACPI_BIOS_ERROR((AE_INFO,
- "Invalid signature 0x%X for ACPI table, expected [%s]",
- *ACPI_CAST_PTR(u32, table->signature),
- signature));
- goto unmap_and_exit;
- }
-
- /*
- * Initialize the table entry. Set the pointer to NULL, since the
- * table is not fully mapped at this time.
- */
- table_desc = &acpi_gbl_root_table_list.tables[table_index];
-
- table_desc->address = address;
- table_desc->pointer = NULL;
- table_desc->length = table->length;
- table_desc->flags = ACPI_TABLE_ORIGIN_MAPPED;
- ACPI_MOVE_32_TO_32(table_desc->signature.ascii, table->signature);
-
- /*
- * ACPI Table Override:
- *
- * Before we install the table, let the host OS override it with a new
- * one if desired. Any table within the RSDT/XSDT can be replaced,
- * including the DSDT which is pointed to by the FADT.
- *
- * NOTE: If the table is overridden, then final_table will contain a
- * mapped pointer to the full new table. If the table is not overridden,
- * or if there has been a physical override, then the table will be
- * fully mapped later (in verify table). In any case, we must
- * unmap the header that was mapped above.
- */
- final_table = acpi_tb_table_override(table, table_desc);
- if (!final_table) {
- final_table = table; /* There was no override */
- }
-
- acpi_tb_print_table_header(table_desc->address, final_table);
-
- /* Set the global integer width (based upon revision of the DSDT) */
-
- if (table_index == ACPI_TABLE_INDEX_DSDT) {
- acpi_ut_set_integer_width(final_table->revision);
- }
-
- /*
- * If we have a physical override during this early loading of the ACPI
- * tables, unmap the table for now. It will be mapped again later when
- * it is actually used. This supports very early loading of ACPI tables,
- * before virtual memory is fully initialized and running within the
- * host OS. Note: A logical override has the ACPI_TABLE_ORIGIN_OVERRIDE
- * flag set and will not be deleted below.
- */
- if (final_table != table) {
- acpi_tb_delete_table(table_desc);
- }
-
-unmap_and_exit:
-
- /* Always unmap the table header that we mapped above */
-
- acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_tb_get_root_table_entry
*
* PARAMETERS: table_entry - Pointer to the RSDT/XSDT table entry
@@ -357,87 +249,6 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size)
/*******************************************************************************
*
- * FUNCTION: acpi_tb_validate_xsdt
- *
- * PARAMETERS: address - Physical address of the XSDT (from RSDP)
- *
- * RETURN: Status. AE_OK if the table appears to be valid.
- *
- * DESCRIPTION: Validate an XSDT to ensure that it is of minimum size and does
- * not contain any NULL entries. A problem that is seen in the
- * field is that the XSDT exists, but is actually useless because
- * of one or more (or all) NULL entries.
- *
- ******************************************************************************/
-
-static acpi_status acpi_tb_validate_xsdt(acpi_physical_address xsdt_address)
-{
- struct acpi_table_header *table;
- u8 *next_entry;
- acpi_physical_address address;
- u32 length;
- u32 entry_count;
- acpi_status status;
- u32 i;
-
- /* Get the XSDT length */
-
- table =
- acpi_os_map_memory(xsdt_address, sizeof(struct acpi_table_header));
- if (!table) {
- return (AE_NO_MEMORY);
- }
-
- length = table->length;
- acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
-
- /*
- * Minimum XSDT length is the size of the standard ACPI header
- * plus one physical address entry
- */
- if (length < (sizeof(struct acpi_table_header) + ACPI_XSDT_ENTRY_SIZE)) {
- return (AE_INVALID_TABLE_LENGTH);
- }
-
- /* Map the entire XSDT */
-
- table = acpi_os_map_memory(xsdt_address, length);
- if (!table) {
- return (AE_NO_MEMORY);
- }
-
- /* Get the number of entries and pointer to first entry */
-
- status = AE_OK;
- next_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header));
- entry_count = (u32)((table->length - sizeof(struct acpi_table_header)) /
- ACPI_XSDT_ENTRY_SIZE);
-
- /* Validate each entry (physical address) within the XSDT */
-
- for (i = 0; i < entry_count; i++) {
- address =
- acpi_tb_get_root_table_entry(next_entry,
- ACPI_XSDT_ENTRY_SIZE);
- if (!address) {
-
- /* Detected a NULL entry, XSDT is invalid */
-
- status = AE_NULL_ENTRY;
- break;
- }
-
- next_entry += ACPI_XSDT_ENTRY_SIZE;
- }
-
- /* Unmap table */
-
- acpi_os_unmap_memory(table, length);
- return (status);
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_tb_parse_root_table
*
* PARAMETERS: rsdp - Pointer to the RSDP
@@ -461,10 +272,10 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
u32 table_count;
struct acpi_table_header *table;
acpi_physical_address address;
- acpi_physical_address rsdt_address;
u32 length;
u8 *table_entry;
acpi_status status;
+ u32 table_index;
ACPI_FUNCTION_TRACE(tb_parse_root_table);
@@ -489,14 +300,11 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
* as per the ACPI specification.
*/
address = (acpi_physical_address) rsdp->xsdt_physical_address;
- rsdt_address =
- (acpi_physical_address) rsdp->rsdt_physical_address;
table_entry_size = ACPI_XSDT_ENTRY_SIZE;
} else {
/* Root table is an RSDT (32-bit physical addresses) */
address = (acpi_physical_address) rsdp->rsdt_physical_address;
- rsdt_address = address;
table_entry_size = ACPI_RSDT_ENTRY_SIZE;
}
@@ -506,24 +314,6 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
*/
acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
- /*
- * If it is present and used, validate the XSDT for access/size
- * and ensure that all table entries are at least non-NULL
- */
- if (table_entry_size == ACPI_XSDT_ENTRY_SIZE) {
- status = acpi_tb_validate_xsdt(address);
- if (ACPI_FAILURE(status)) {
- ACPI_BIOS_WARNING((AE_INFO,
- "XSDT is invalid (%s), using RSDT",
- acpi_format_exception(status)));
-
- /* Fall back to the RSDT */
-
- address = rsdt_address;
- table_entry_size = ACPI_RSDT_ENTRY_SIZE;
- }
- }
-
/* Map the RSDT/XSDT table header to get the full table length */
table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
@@ -576,55 +366,36 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
/* Initialize the root table array from the RSDT/XSDT */
for (i = 0; i < table_count; i++) {
- if (acpi_gbl_root_table_list.current_table_count >=
- acpi_gbl_root_table_list.max_table_count) {
-
- /* There is no more room in the root table array, attempt resize */
-
- status = acpi_tb_resize_root_table_list();
- if (ACPI_FAILURE(status)) {
- ACPI_WARNING((AE_INFO,
- "Truncating %u table entries!",
- (unsigned) (table_count -
- (acpi_gbl_root_table_list.
- current_table_count -
- 2))));
- break;
- }
- }
/* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
- acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.
- current_table_count].address =
+ address =
acpi_tb_get_root_table_entry(table_entry, table_entry_size);
- table_entry += table_entry_size;
- acpi_gbl_root_table_list.current_table_count++;
- }
-
- /*
- * It is not possible to map more than one entry in some environments,
- * so unmap the root table here before mapping other tables
- */
- acpi_os_unmap_memory(table, length);
+ /* Skip NULL entries in RSDT/XSDT */
- /*
- * Complete the initialization of the root table array by examining
- * the header of each table
- */
- for (i = 2; i < acpi_gbl_root_table_list.current_table_count; i++) {
- acpi_tb_install_table(acpi_gbl_root_table_list.tables[i].
- address, NULL, i);
+ if (!address) {
+ goto next_table;
+ }
- /* Special case for FADT - validate it then get the DSDT and FACS */
+ status = acpi_tb_install_standard_table(address,
+ ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
+ FALSE, TRUE,
+ &table_index);
- if (ACPI_COMPARE_NAME
- (&acpi_gbl_root_table_list.tables[i].signature,
- ACPI_SIG_FADT)) {
- acpi_tb_parse_fadt(i);
+ if (ACPI_SUCCESS(status) &&
+ ACPI_COMPARE_NAME(&acpi_gbl_root_table_list.
+ tables[table_index].signature,
+ ACPI_SIG_FADT)) {
+ acpi_tb_parse_fadt(table_index);
}
+
+next_table:
+
+ table_entry += table_entry_size;
}
+ acpi_os_unmap_memory(table, length);
+
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c
index a1593159d9ea..6482b0ded652 100644
--- a/drivers/acpi/acpica/tbxface.c
+++ b/drivers/acpi/acpica/tbxface.c
@@ -206,8 +206,8 @@ acpi_status
acpi_get_table_header(char *signature,
u32 instance, struct acpi_table_header *out_table_header)
{
- u32 i;
- u32 j;
+ u32 i;
+ u32 j;
struct acpi_table_header *header;
/* Parameter validation */
@@ -233,7 +233,7 @@ acpi_get_table_header(char *signature,
if (!acpi_gbl_root_table_list.tables[i].pointer) {
if ((acpi_gbl_root_table_list.tables[i].flags &
ACPI_TABLE_ORIGIN_MASK) ==
- ACPI_TABLE_ORIGIN_MAPPED) {
+ ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL) {
header =
acpi_os_map_memory(acpi_gbl_root_table_list.
tables[i].address,
@@ -321,8 +321,8 @@ acpi_get_table_with_size(char *signature,
u32 instance, struct acpi_table_header **out_table,
acpi_size *tbl_size)
{
- u32 i;
- u32 j;
+ u32 i;
+ u32 j;
acpi_status status;
/* Parameter validation */
@@ -346,7 +346,7 @@ acpi_get_table_with_size(char *signature,
}
status =
- acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]);
+ acpi_tb_validate_table(&acpi_gbl_root_table_list.tables[i]);
if (ACPI_SUCCESS(status)) {
*out_table = acpi_gbl_root_table_list.tables[i].pointer;
*tbl_size = acpi_gbl_root_table_list.tables[i].length;
@@ -390,7 +390,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_table)
*
******************************************************************************/
acpi_status
-acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table)
+acpi_get_table_by_index(u32 table_index, struct acpi_table_header ** table)
{
acpi_status status;
@@ -416,8 +416,8 @@ acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table)
/* Table is not mapped, map it */
status =
- acpi_tb_verify_table(&acpi_gbl_root_table_list.
- tables[table_index]);
+ acpi_tb_validate_table(&acpi_gbl_root_table_list.
+ tables[table_index]);
if (ACPI_FAILURE(status)) {
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
return_ACPI_STATUS(status);
diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c
index 0909420fc776..ab5308b81aa8 100644
--- a/drivers/acpi/acpica/tbxfload.c
+++ b/drivers/acpi/acpica/tbxfload.c
@@ -117,7 +117,7 @@ static acpi_status acpi_tb_load_namespace(void)
tables[ACPI_TABLE_INDEX_DSDT].signature),
ACPI_SIG_DSDT)
||
- ACPI_FAILURE(acpi_tb_verify_table
+ ACPI_FAILURE(acpi_tb_validate_table
(&acpi_gbl_root_table_list.
tables[ACPI_TABLE_INDEX_DSDT]))) {
status = AE_NO_ACPI_TABLES;
@@ -128,7 +128,7 @@ static acpi_status acpi_tb_load_namespace(void)
* Save the DSDT pointer for simple access. This is the mapped memory
* address. We must take care here because the address of the .Tables
* array can change dynamically as tables are loaded at run-time. Note:
- * .Pointer field is not validated until after call to acpi_tb_verify_table.
+ * .Pointer field is not validated until after call to acpi_tb_validate_table.
*/
acpi_gbl_DSDT =
acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer;
@@ -174,24 +174,11 @@ static acpi_status acpi_tb_load_namespace(void)
(acpi_gbl_root_table_list.tables[i].
signature), ACPI_SIG_PSDT))
||
- ACPI_FAILURE(acpi_tb_verify_table
+ ACPI_FAILURE(acpi_tb_validate_table
(&acpi_gbl_root_table_list.tables[i]))) {
continue;
}
- /*
- * Optionally do not load any SSDTs from the RSDT/XSDT. This can
- * be useful for debugging ACPI problems on some machines.
- */
- if (acpi_gbl_disable_ssdt_table_load) {
- ACPI_INFO((AE_INFO, "Ignoring %4.4s at %p",
- acpi_gbl_root_table_list.tables[i].signature.
- ascii, ACPI_CAST_PTR(void,
- acpi_gbl_root_table_list.
- tables[i].address)));
- continue;
- }
-
/* Ignore errors while loading tables, get as many as possible */
(void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
@@ -208,6 +195,45 @@ unlock_and_exit:
/*******************************************************************************
*
+ * FUNCTION: acpi_install_table
+ *
+ * PARAMETERS: address - Address of the ACPI table to be installed.
+ * physical - Whether the address is a physical table
+ * address or not
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Dynamically install an ACPI table.
+ * Note: This function should only be invoked after
+ * acpi_initialize_tables() and before acpi_load_tables().
+ *
+ ******************************************************************************/
+
+acpi_status __init
+acpi_install_table(acpi_physical_address address, u8 physical)
+{
+ acpi_status status;
+ u8 flags;
+ u32 table_index;
+
+ ACPI_FUNCTION_TRACE(acpi_install_table);
+
+ if (physical) {
+ flags = ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL;
+ } else {
+ flags = ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL;
+ }
+
+ status = acpi_tb_install_standard_table(address, flags,
+ FALSE, FALSE, &table_index);
+
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL_INIT(acpi_install_table)
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_load_table
*
* PARAMETERS: table - Pointer to a buffer containing the ACPI
@@ -222,11 +248,9 @@ unlock_and_exit:
* to ensure that the table is not deleted or unmapped.
*
******************************************************************************/
-
acpi_status acpi_load_table(struct acpi_table_header *table)
{
acpi_status status;
- struct acpi_table_desc table_desc;
u32 table_index;
ACPI_FUNCTION_TRACE(acpi_load_table);
@@ -237,14 +261,6 @@ acpi_status acpi_load_table(struct acpi_table_header *table)
return_ACPI_STATUS(AE_BAD_PARAMETER);
}
- /* Init local table descriptor */
-
- ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
- table_desc.address = ACPI_PTR_TO_PHYSADDR(table);
- table_desc.pointer = table;
- table_desc.length = table->length;
- table_desc.flags = ACPI_TABLE_ORIGIN_UNKNOWN;
-
/* Must acquire the interpreter lock during this operation */
status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
@@ -255,7 +271,24 @@ acpi_status acpi_load_table(struct acpi_table_header *table)
/* Install the table and load it into the namespace */
ACPI_INFO((AE_INFO, "Host-directed Dynamic ACPI Table Load:"));
- status = acpi_tb_add_table(&table_desc, &table_index);
+ (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+ status = acpi_tb_install_standard_table(ACPI_PTR_TO_PHYSADDR(table),
+ ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL,
+ TRUE, FALSE, &table_index);
+
+ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+ if (ACPI_FAILURE(status)) {
+ goto unlock_and_exit;
+ }
+
+ /*
+ * Note: Now table is "INSTALLED", it must be validated before
+ * using.
+ */
+ status =
+ acpi_tb_validate_table(&acpi_gbl_root_table_list.
+ tables[table_index]);
if (ACPI_FAILURE(status)) {
goto unlock_and_exit;
}
diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c
index fbfa9eca011f..90ec37c473c6 100644
--- a/drivers/acpi/acpica/utdecode.c
+++ b/drivers/acpi/acpica/utdecode.c
@@ -462,7 +462,7 @@ char *acpi_ut_get_mutex_name(u32 mutex_id)
/* Names for Notify() values, used for debug output */
-static const char *acpi_gbl_notify_value_names[ACPI_NOTIFY_MAX + 1] = {
+static const char *acpi_gbl_generic_notify[ACPI_NOTIFY_MAX + 1] = {
/* 00 */ "Bus Check",
/* 01 */ "Device Check",
/* 02 */ "Device Wake",
@@ -473,23 +473,75 @@ static const char *acpi_gbl_notify_value_names[ACPI_NOTIFY_MAX + 1] = {
/* 07 */ "Power Fault",
/* 08 */ "Capabilities Check",
/* 09 */ "Device PLD Check",
- /* 10 */ "Reserved",
- /* 11 */ "System Locality Update",
- /* 12 */ "Shutdown Request"
+ /* 0A */ "Reserved",
+ /* 0B */ "System Locality Update",
+ /* 0C */ "Shutdown Request"
};
-const char *acpi_ut_get_notify_name(u32 notify_value)
+static const char *acpi_gbl_device_notify[4] = {
+ /* 80 */ "Status Change",
+ /* 81 */ "Information Change",
+ /* 82 */ "Device-Specific Change",
+ /* 83 */ "Device-Specific Change"
+};
+
+static const char *acpi_gbl_processor_notify[4] = {
+ /* 80 */ "Performance Capability Change",
+ /* 81 */ "C-State Change",
+ /* 82 */ "Throttling Capability Change",
+ /* 83 */ "Device-Specific Change"
+};
+
+static const char *acpi_gbl_thermal_notify[4] = {
+ /* 80 */ "Thermal Status Change",
+ /* 81 */ "Thermal Trip Point Change",
+ /* 82 */ "Thermal Device List Change",
+ /* 83 */ "Thermal Relationship Change"
+};
+
+const char *acpi_ut_get_notify_name(u32 notify_value, acpi_object_type type)
{
+ /* 00 - 0C are common to all object types */
+
if (notify_value <= ACPI_NOTIFY_MAX) {
- return (acpi_gbl_notify_value_names[notify_value]);
- } else if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
+ return (acpi_gbl_generic_notify[notify_value]);
+ }
+
+ /* 0D - 7F are reserved */
+
+ if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
return ("Reserved");
- } else if (notify_value <= ACPI_MAX_DEVICE_SPECIFIC_NOTIFY) {
- return ("Device Specific");
- } else {
- return ("Hardware Specific");
}
+
+ /* 80 - 83 are per-object-type */
+
+ if (notify_value <= 0x83) {
+ switch (type) {
+ case ACPI_TYPE_ANY:
+ case ACPI_TYPE_DEVICE:
+ return (acpi_gbl_device_notify[notify_value - 0x80]);
+
+ case ACPI_TYPE_PROCESSOR:
+ return (acpi_gbl_processor_notify[notify_value - 0x80]);
+
+ case ACPI_TYPE_THERMAL:
+ return (acpi_gbl_thermal_notify[notify_value - 0x80]);
+
+ default:
+ return ("Target object type does not support notifies");
+ }
+ }
+
+ /* 84 - BF are device-specific */
+
+ if (notify_value <= ACPI_MAX_DEVICE_SPECIFIC_NOTIFY) {
+ return ("Device-Specific");
+ }
+
+ /* C0 and above are hardware-specific */
+
+ return ("Hardware-Specific");
}
#endif
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index f3abeae9d2f8..d69be3cb3fae 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -55,28 +55,7 @@ ACPI_MODULE_NAME("utglobal")
* Static global variable initialization.
*
******************************************************************************/
-/* Debug output control masks */
-u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT;
-
-u32 acpi_dbg_layer = 0;
-
-/* acpi_gbl_FADT is a local copy of the FADT, converted to a common format. */
-
-struct acpi_table_fadt acpi_gbl_FADT;
-u32 acpi_gbl_trace_flags;
-acpi_name acpi_gbl_trace_method_name;
-u8 acpi_gbl_system_awake_and_running;
-u32 acpi_current_gpe_count;
-
-/*
- * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning
- * that the ACPI hardware is no longer required. A flag in the FADT indicates
- * a reduced HW machine, and that flag is duplicated here for convenience.
- */
-u8 acpi_gbl_reduced_hardware;
-
/* Various state name strings */
-
const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = {
"\\_S0_",
"\\_S1_",
@@ -337,7 +316,6 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_acpi_hardware_present = TRUE;
acpi_gbl_last_owner_id_index = 0;
acpi_gbl_next_owner_id_offset = 0;
- acpi_gbl_trace_method_name = 0;
acpi_gbl_trace_dbg_level = 0;
acpi_gbl_trace_dbg_layer = 0;
acpi_gbl_debugger_configuration = DEBUGGER_THREADING;
@@ -377,9 +355,7 @@ acpi_status acpi_ut_init_globals(void)
acpi_gbl_disable_mem_tracking = FALSE;
#endif
-#ifdef ACPI_DEBUGGER
- acpi_gbl_db_terminate_threads = FALSE;
-#endif
+ ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = FALSE);
return_ACPI_STATUS(AE_OK);
}
diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c
index 77219336c7e0..6dc54b3c28b0 100644
--- a/drivers/acpi/acpica/utstring.c
+++ b/drivers/acpi/acpica/utstring.c
@@ -353,7 +353,7 @@ void acpi_ut_print_string(char *string, u16 max_length)
}
acpi_os_printf("\"");
- for (i = 0; string[i] && (i < max_length); i++) {
+ for (i = 0; (i < max_length) && string[i]; i++) {
/* Escape sequences */
diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c
index edd861102f1b..88ef77f3cf88 100644
--- a/drivers/acpi/acpica/utxferror.c
+++ b/drivers/acpi/acpica/utxferror.c
@@ -53,6 +53,7 @@ ACPI_MODULE_NAME("utxferror")
* This module is used for the in-kernel ACPICA as well as the ACPICA
* tools/applications.
*/
+#ifndef ACPI_NO_ERROR_MESSAGES /* Entire module */
/*******************************************************************************
*
* FUNCTION: acpi_error
@@ -249,3 +250,4 @@ acpi_bios_warning(const char *module_name,
}
ACPI_EXPORT_SYMBOL(acpi_bios_warning)
+#endif /* ACPI_NO_ERROR_MESSAGES */
diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c
index 1be6f5564485..a095d4f858da 100644
--- a/drivers/acpi/apei/einj.c
+++ b/drivers/acpi/apei/einj.c
@@ -202,7 +202,7 @@ static void check_vendor_extension(u64 paddr,
if (!offset)
return;
- v = acpi_os_map_memory(paddr + offset, sizeof(*v));
+ v = acpi_os_map_iomem(paddr + offset, sizeof(*v));
if (!v)
return;
sbdf = v->pcie_sbdf;
@@ -210,7 +210,7 @@ static void check_vendor_extension(u64 paddr,
sbdf >> 24, (sbdf >> 16) & 0xff,
(sbdf >> 11) & 0x1f, (sbdf >> 8) & 0x7,
v->vendor_id, v->device_id, v->rev_id);
- acpi_os_unmap_memory(v, sizeof(*v));
+ acpi_os_unmap_iomem(v, sizeof(*v));
}
static void *einj_get_parameter_address(void)
@@ -236,7 +236,7 @@ static void *einj_get_parameter_address(void)
if (pa_v5) {
struct set_error_type_with_address *v5param;
- v5param = acpi_os_map_memory(pa_v5, sizeof(*v5param));
+ v5param = acpi_os_map_iomem(pa_v5, sizeof(*v5param));
if (v5param) {
acpi5 = 1;
check_vendor_extension(pa_v5, v5param);
@@ -246,11 +246,11 @@ static void *einj_get_parameter_address(void)
if (param_extension && pa_v4) {
struct einj_parameter *v4param;
- v4param = acpi_os_map_memory(pa_v4, sizeof(*v4param));
+ v4param = acpi_os_map_iomem(pa_v4, sizeof(*v4param));
if (!v4param)
return NULL;
if (v4param->reserved1 || v4param->reserved2) {
- acpi_os_unmap_memory(v4param, sizeof(*v4param));
+ acpi_os_unmap_iomem(v4param, sizeof(*v4param));
return NULL;
}
return v4param;
@@ -794,7 +794,7 @@ err_unmap:
sizeof(struct set_error_type_with_address) :
sizeof(struct einj_parameter);
- acpi_os_unmap_memory(einj_param, size);
+ acpi_os_unmap_iomem(einj_param, size);
}
apei_exec_post_unmap_gars(&ctx);
err_release:
@@ -816,7 +816,7 @@ static void __exit einj_exit(void)
sizeof(struct set_error_type_with_address) :
sizeof(struct einj_parameter);
- acpi_os_unmap_memory(einj_param, size);
+ acpi_os_unmap_iomem(einj_param, size);
}
einj_exec_ctx_init(&ctx);
apei_exec_post_unmap_gars(&ctx);
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 6e7b2a12860d..e48fc98e71c4 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -56,6 +56,10 @@
/* Battery power unit: 0 means mW, 1 means mA */
#define ACPI_BATTERY_POWER_UNIT_MA 1
+#define ACPI_BATTERY_STATE_DISCHARGING 0x1
+#define ACPI_BATTERY_STATE_CHARGING 0x2
+#define ACPI_BATTERY_STATE_CRITICAL 0x4
+
#define _COMPONENT ACPI_BATTERY_COMPONENT
ACPI_MODULE_NAME("battery");
@@ -169,7 +173,7 @@ static int acpi_battery_get_state(struct acpi_battery *battery);
static int acpi_battery_is_charged(struct acpi_battery *battery)
{
- /* either charging or discharging */
+ /* charging, discharging or critical low */
if (battery->state != 0)
return 0;
@@ -204,9 +208,9 @@ static int acpi_battery_get_property(struct power_supply *psy,
return -ENODEV;
switch (psp) {
case POWER_SUPPLY_PROP_STATUS:
- if (battery->state & 0x01)
+ if (battery->state & ACPI_BATTERY_STATE_DISCHARGING)
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
- else if (battery->state & 0x02)
+ else if (battery->state & ACPI_BATTERY_STATE_CHARGING)
val->intval = POWER_SUPPLY_STATUS_CHARGING;
else if (acpi_battery_is_charged(battery))
val->intval = POWER_SUPPLY_STATUS_FULL;
@@ -269,6 +273,17 @@ static int acpi_battery_get_property(struct power_supply *psy,
else
val->intval = 0;
break;
+ case POWER_SUPPLY_PROP_CAPACITY_LEVEL:
+ if (battery->state & ACPI_BATTERY_STATE_CRITICAL)
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL;
+ else if (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
+ (battery->capacity_now <= battery->alarm))
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_LOW;
+ else if (acpi_battery_is_charged(battery))
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_FULL;
+ else
+ val->intval = POWER_SUPPLY_CAPACITY_LEVEL_NORMAL;
+ break;
case POWER_SUPPLY_PROP_MODEL_NAME:
val->strval = battery->model_number;
break;
@@ -296,6 +311,7 @@ static enum power_supply_property charge_battery_props[] = {
POWER_SUPPLY_PROP_CHARGE_FULL,
POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
POWER_SUPPLY_PROP_SERIAL_NUMBER,
@@ -313,6 +329,7 @@ static enum power_supply_property energy_battery_props[] = {
POWER_SUPPLY_PROP_ENERGY_FULL,
POWER_SUPPLY_PROP_ENERGY_NOW,
POWER_SUPPLY_PROP_CAPACITY,
+ POWER_SUPPLY_PROP_CAPACITY_LEVEL,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER,
POWER_SUPPLY_PROP_SERIAL_NUMBER,
@@ -605,7 +622,8 @@ static int sysfs_add_battery(struct acpi_battery *battery)
battery->bat.type = POWER_SUPPLY_TYPE_BATTERY;
battery->bat.get_property = acpi_battery_get_property;
- result = power_supply_register(&battery->device->dev, &battery->bat);
+ result = power_supply_register_no_ws(&battery->device->dev, &battery->bat);
+
if (result)
return result;
return device_create_file(battery->bat.dev, &alarm_attr);
@@ -696,7 +714,7 @@ static void acpi_battery_quirks(struct acpi_battery *battery)
}
}
-static int acpi_battery_update(struct acpi_battery *battery)
+static int acpi_battery_update(struct acpi_battery *battery, bool resume)
{
int result, old_present = acpi_battery_present(battery);
result = acpi_battery_get_status(battery);
@@ -707,6 +725,10 @@ static int acpi_battery_update(struct acpi_battery *battery)
battery->update_time = 0;
return 0;
}
+
+ if (resume)
+ return 0;
+
if (!battery->update_time ||
old_present != acpi_battery_present(battery)) {
result = acpi_battery_get_info(battery);
@@ -720,7 +742,19 @@ static int acpi_battery_update(struct acpi_battery *battery)
return result;
}
result = acpi_battery_get_state(battery);
+ if (result)
+ return result;
acpi_battery_quirks(battery);
+
+ /*
+ * Wakeup the system if battery is critical low
+ * or lower than the alarm level
+ */
+ if ((battery->state & ACPI_BATTERY_STATE_CRITICAL) ||
+ (test_bit(ACPI_BATTERY_ALARM_PRESENT, &battery->flags) &&
+ (battery->capacity_now <= battery->alarm)))
+ pm_wakeup_event(&battery->device->dev, 0);
+
return result;
}
@@ -915,7 +949,7 @@ static print_func acpi_print_funcs[ACPI_BATTERY_NUMFILES] = {
static int acpi_battery_read(int fid, struct seq_file *seq)
{
struct acpi_battery *battery = seq->private;
- int result = acpi_battery_update(battery);
+ int result = acpi_battery_update(battery, false);
return acpi_print_funcs[fid](seq, result);
}
@@ -1030,7 +1064,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event)
old = battery->bat.dev;
if (event == ACPI_BATTERY_NOTIFY_INFO)
acpi_battery_refresh(battery);
- acpi_battery_update(battery);
+ acpi_battery_update(battery, false);
acpi_bus_generate_netlink_event(device->pnp.device_class,
dev_name(&device->dev), event,
acpi_battery_present(battery));
@@ -1045,13 +1079,27 @@ static int battery_notify(struct notifier_block *nb,
{
struct acpi_battery *battery = container_of(nb, struct acpi_battery,
pm_nb);
+ int result;
+
switch (mode) {
case PM_POST_HIBERNATION:
case PM_POST_SUSPEND:
- if (battery->bat.dev) {
- sysfs_remove_battery(battery);
- sysfs_add_battery(battery);
- }
+ if (!acpi_battery_present(battery))
+ return 0;
+
+ if (!battery->bat.dev) {
+ result = acpi_battery_get_info(battery);
+ if (result)
+ return result;
+
+ result = sysfs_add_battery(battery);
+ if (result)
+ return result;
+ } else
+ acpi_battery_refresh(battery);
+
+ acpi_battery_init_alarm(battery);
+ acpi_battery_get_state(battery);
break;
}
@@ -1087,7 +1135,7 @@ static int acpi_battery_add(struct acpi_device *device)
mutex_init(&battery->sysfs_lock);
if (acpi_has_method(battery->device->handle, "_BIX"))
set_bit(ACPI_BATTERY_XINFO_PRESENT, &battery->flags);
- result = acpi_battery_update(battery);
+ result = acpi_battery_update(battery, false);
if (result)
goto fail;
#ifdef CONFIG_ACPI_PROCFS_POWER
@@ -1107,6 +1155,8 @@ static int acpi_battery_add(struct acpi_device *device)
battery->pm_nb.notifier_call = battery_notify;
register_pm_notifier(&battery->pm_nb);
+ device_init_wakeup(&device->dev, 1);
+
return result;
fail:
@@ -1123,6 +1173,7 @@ static int acpi_battery_remove(struct acpi_device *device)
if (!device || !acpi_driver_data(device))
return -EINVAL;
+ device_init_wakeup(&device->dev, 0);
battery = acpi_driver_data(device);
unregister_pm_notifier(&battery->pm_nb);
#ifdef CONFIG_ACPI_PROCFS_POWER
@@ -1149,7 +1200,7 @@ static int acpi_battery_resume(struct device *dev)
return -EINVAL;
battery->update_time = 0;
- acpi_battery_update(battery);
+ acpi_battery_update(battery, true);
return 0;
}
#else
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index cf925c4f36b7..c5bc8cfe09fa 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -52,6 +52,12 @@ struct proc_dir_entry *acpi_root_dir;
EXPORT_SYMBOL(acpi_root_dir);
#ifdef CONFIG_X86
+#ifdef CONFIG_ACPI_CUSTOM_DSDT
+static inline int set_copy_dsdt(const struct dmi_system_id *id)
+{
+ return 0;
+}
+#else
static int set_copy_dsdt(const struct dmi_system_id *id)
{
printk(KERN_NOTICE "%s detected - "
@@ -59,6 +65,7 @@ static int set_copy_dsdt(const struct dmi_system_id *id)
acpi_gbl_copy_dsdt_locally = 1;
return 0;
}
+#endif
static struct dmi_system_id dsdt_dmi_table[] __initdata = {
/*
@@ -132,6 +139,21 @@ void acpi_bus_private_data_handler(acpi_handle handle,
}
EXPORT_SYMBOL(acpi_bus_private_data_handler);
+int acpi_bus_attach_private_data(acpi_handle handle, void *data)
+{
+ acpi_status status;
+
+ status = acpi_attach_data(handle,
+ acpi_bus_private_data_handler, data);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_debug(handle, "Error attaching device data\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_attach_private_data);
+
int acpi_bus_get_private_data(acpi_handle handle, void **data)
{
acpi_status status;
@@ -140,15 +162,20 @@ int acpi_bus_get_private_data(acpi_handle handle, void **data)
return -EINVAL;
status = acpi_get_data(handle, acpi_bus_private_data_handler, data);
- if (ACPI_FAILURE(status) || !*data) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
- handle));
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_debug(handle, "No context for object\n");
return -ENODEV;
}
return 0;
}
-EXPORT_SYMBOL(acpi_bus_get_private_data);
+EXPORT_SYMBOL_GPL(acpi_bus_get_private_data);
+
+void acpi_bus_detach_private_data(acpi_handle handle)
+{
+ acpi_detach_data(handle, acpi_bus_private_data_handler);
+}
+EXPORT_SYMBOL_GPL(acpi_bus_detach_private_data);
void acpi_bus_no_hotplug(acpi_handle handle)
{
@@ -340,16 +367,18 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
{
struct acpi_device *adev;
struct acpi_driver *driver;
- acpi_status status;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE;
+ bool hotplug_event = false;
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
acpi_handle_debug(handle, "ACPI_NOTIFY_BUS_CHECK event\n");
+ hotplug_event = true;
break;
case ACPI_NOTIFY_DEVICE_CHECK:
acpi_handle_debug(handle, "ACPI_NOTIFY_DEVICE_CHECK event\n");
+ hotplug_event = true;
break;
case ACPI_NOTIFY_DEVICE_WAKE:
@@ -358,6 +387,7 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
case ACPI_NOTIFY_EJECT_REQUEST:
acpi_handle_debug(handle, "ACPI_NOTIFY_EJECT_REQUEST event\n");
+ hotplug_event = true;
break;
case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
@@ -393,16 +423,9 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
(driver->flags & ACPI_DRIVER_ALL_NOTIFY_EVENTS))
driver->ops.notify(adev, type);
- switch (type) {
- case ACPI_NOTIFY_BUS_CHECK:
- case ACPI_NOTIFY_DEVICE_CHECK:
- case ACPI_NOTIFY_EJECT_REQUEST:
- status = acpi_hotplug_schedule(adev, type);
- if (ACPI_SUCCESS(status))
- return;
- default:
- break;
- }
+ if (hotplug_event && ACPI_SUCCESS(acpi_hotplug_schedule(adev, type)))
+ return;
+
acpi_bus_put_acpi_device(adev);
return;
@@ -466,6 +489,9 @@ void __init acpi_early_init(void)
printk(KERN_INFO PREFIX "Core revision %08x\n", ACPI_CA_VERSION);
+ /* It's safe to verify table checksums during late stage */
+ acpi_gbl_verify_table_checksum = TRUE;
+
/* enable workarounds, unless strict ACPI spec. compliance */
if (!acpi_strict)
acpi_gbl_enable_interpreter_slack = TRUE;
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 63119d09b354..76f7cff64594 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -41,6 +41,8 @@ static const struct acpi_device_id container_device_ids[] = {
{"", 0},
};
+#ifdef CONFIG_ACPI_CONTAINER
+
static int acpi_container_offline(struct container_dev *cdev)
{
struct acpi_device *adev = ACPI_COMPANION(&cdev->dev);
@@ -109,5 +111,18 @@ static struct acpi_scan_handler container_handler = {
void __init acpi_container_init(void)
{
+ acpi_scan_add_handler(&container_handler);
+}
+
+#else
+
+static struct acpi_scan_handler container_handler = {
+ .ids = container_device_ids,
+};
+
+void __init acpi_container_init(void)
+{
acpi_scan_add_handler_with_hotplug(&container_handler, "container");
}
+
+#endif /* CONFIG_ACPI_CONTAINER */
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index d047739f3380..49a51277f81d 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -900,18 +900,47 @@ EXPORT_SYMBOL_GPL(acpi_dev_resume_early);
*/
int acpi_subsys_prepare(struct device *dev)
{
- /*
- * Devices having power.ignore_children set may still be necessary for
- * suspending their children in the next phase of device suspend.
- */
- if (dev->power.ignore_children)
- pm_runtime_resume(dev);
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+ u32 sys_target;
+ int ret, state;
+
+ ret = pm_generic_prepare(dev);
+ if (ret < 0)
+ return ret;
+
+ if (!adev || !pm_runtime_suspended(dev)
+ || device_may_wakeup(dev) != !!adev->wakeup.prepare_count)
+ return 0;
+
+ sys_target = acpi_target_system_state();
+ if (sys_target == ACPI_STATE_S0)
+ return 1;
- return pm_generic_prepare(dev);
+ if (adev->power.flags.dsw_present)
+ return 0;
+
+ ret = acpi_dev_pm_get_state(dev, adev, sys_target, NULL, &state);
+ return !ret && state == adev->power.state;
}
EXPORT_SYMBOL_GPL(acpi_subsys_prepare);
/**
+ * acpi_subsys_complete - Finalize device's resume during system resume.
+ * @dev: Device to handle.
+ */
+void acpi_subsys_complete(struct device *dev)
+{
+ /*
+ * If the device had been runtime-suspended before the system went into
+ * the sleep state it is going out of and it has never been resumed till
+ * now, resume it in case the firmware powered it up.
+ */
+ if (dev->power.direct_complete)
+ pm_request_resume(dev);
+}
+EXPORT_SYMBOL_GPL(acpi_subsys_complete);
+
+/**
* acpi_subsys_suspend - Run the device driver's suspend callback.
* @dev: Device to handle.
*
@@ -923,6 +952,7 @@ int acpi_subsys_suspend(struct device *dev)
pm_runtime_resume(dev);
return pm_generic_suspend(dev);
}
+EXPORT_SYMBOL_GPL(acpi_subsys_suspend);
/**
* acpi_subsys_suspend_late - Suspend device using ACPI.
@@ -968,6 +998,7 @@ int acpi_subsys_freeze(struct device *dev)
pm_runtime_resume(dev);
return pm_generic_freeze(dev);
}
+EXPORT_SYMBOL_GPL(acpi_subsys_freeze);
#endif /* CONFIG_PM_SLEEP */
@@ -979,6 +1010,7 @@ static struct dev_pm_domain acpi_general_pm_domain = {
#endif
#ifdef CONFIG_PM_SLEEP
.prepare = acpi_subsys_prepare,
+ .complete = acpi_subsys_complete,
.suspend = acpi_subsys_suspend,
.suspend_late = acpi_subsys_suspend_late,
.resume_early = acpi_subsys_resume_early,
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 957391306cbf..7de5b603f272 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -30,12 +30,10 @@ void acpi_pci_root_init(void);
void acpi_pci_link_init(void);
void acpi_processor_init(void);
void acpi_platform_init(void);
+void acpi_pnp_init(void);
int acpi_sysfs_init(void);
-#ifdef CONFIG_ACPI_CONTAINER
void acpi_container_init(void);
-#else
-static inline void acpi_container_init(void) {}
-#endif
+void acpi_memory_hotplug_init(void);
#ifdef CONFIG_ACPI_DOCK
void register_dock_dependent_device(struct acpi_device *adev,
acpi_handle dshandle);
@@ -47,11 +45,6 @@ static inline void register_dock_dependent_device(struct acpi_device *adev,
static inline int dock_notify(struct acpi_device *adev, u32 event) { return -ENODEV; }
static inline void acpi_dock_add(struct acpi_device *adev) {}
#endif
-#ifdef CONFIG_ACPI_HOTPLUG_MEMORY
-void acpi_memory_hotplug_init(void);
-#else
-static inline void acpi_memory_hotplug_init(void) {}
-#endif
#ifdef CONFIG_X86
void acpi_cmos_rtc_init(void);
#else
@@ -72,11 +65,7 @@ int acpi_debugfs_init(void);
#else
static inline void acpi_debugfs_init(void) { return; }
#endif
-#ifdef CONFIG_X86_INTEL_LPSS
void acpi_lpss_init(void);
-#else
-static inline void acpi_lpss_init(void) {}
-#endif
acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src);
bool acpi_queue_hotplug_work(struct work_struct *work);
@@ -180,8 +169,7 @@ static inline void suspend_nvs_restore(void) {}
-------------------------------------------------------------------------- */
struct platform_device;
-int acpi_create_platform_device(struct acpi_device *adev,
- const struct acpi_device_id *id);
+struct platform_device *acpi_create_platform_device(struct acpi_device *adev);
/*--------------------------------------------------------------------------
Video
diff --git a/drivers/acpi/nvs.c b/drivers/acpi/nvs.c
index de4fe03873c5..85287b8fe3aa 100644
--- a/drivers/acpi/nvs.c
+++ b/drivers/acpi/nvs.c
@@ -139,8 +139,8 @@ void suspend_nvs_free(void)
iounmap(entry->kaddr);
entry->unmap = false;
} else {
- acpi_os_unmap_memory(entry->kaddr,
- entry->size);
+ acpi_os_unmap_iomem(entry->kaddr,
+ entry->size);
}
entry->kaddr = NULL;
}
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 6776c599816f..147bc1b91b42 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -355,7 +355,7 @@ static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr)
}
void __iomem *__init_refok
-acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
+acpi_os_map_iomem(acpi_physical_address phys, acpi_size size)
{
struct acpi_ioremap *map;
void __iomem *virt;
@@ -401,10 +401,17 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
list_add_tail_rcu(&map->list, &acpi_ioremaps);
- out:
+out:
mutex_unlock(&acpi_ioremap_lock);
return map->virt + (phys - map->phys);
}
+EXPORT_SYMBOL_GPL(acpi_os_map_iomem);
+
+void *__init_refok
+acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
+{
+ return (void *)acpi_os_map_iomem(phys, size);
+}
EXPORT_SYMBOL_GPL(acpi_os_map_memory);
static void acpi_os_drop_map_ref(struct acpi_ioremap *map)
@@ -422,7 +429,7 @@ static void acpi_os_map_cleanup(struct acpi_ioremap *map)
}
}
-void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
+void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)
{
struct acpi_ioremap *map;
@@ -443,6 +450,12 @@ void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
acpi_os_map_cleanup(map);
}
+EXPORT_SYMBOL_GPL(acpi_os_unmap_iomem);
+
+void __ref acpi_os_unmap_memory(void *virt, acpi_size size)
+{
+ return acpi_os_unmap_iomem((void __iomem *)virt, size);
+}
EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
@@ -464,7 +477,7 @@ int acpi_os_map_generic_address(struct acpi_generic_address *gas)
if (!addr || !gas->bit_width)
return -EINVAL;
- virt = acpi_os_map_memory(addr, gas->bit_width / 8);
+ virt = acpi_os_map_iomem(addr, gas->bit_width / 8);
if (!virt)
return -EIO;
@@ -1770,16 +1783,15 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
}
#endif
-static int __init acpi_no_auto_ssdt_setup(char *s)
+static int __init acpi_no_static_ssdt_setup(char *s)
{
- printk(KERN_NOTICE PREFIX "SSDT auto-load disabled\n");
+ acpi_gbl_disable_ssdt_table_install = TRUE;
+ pr_info("ACPI: static SSDT installation disabled\n");
- acpi_gbl_disable_ssdt_table_load = TRUE;
-
- return 1;
+ return 0;
}
-__setup("acpi_no_auto_ssdt", acpi_no_auto_ssdt_setup);
+early_param("acpi_no_static_ssdt", acpi_no_static_ssdt_setup);
static int __init acpi_disable_return_repair(char *s)
{
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 7f70f3182d50..4fcbd670415c 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -121,6 +121,13 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb,
struct acpi_processor *pr = per_cpu(processors, cpu);
struct acpi_device *device;
+ /*
+ * CPU_STARTING and CPU_DYING must not sleep. Return here since
+ * acpi_bus_get_device() may sleep.
+ */
+ if (action == CPU_STARTING || action == CPU_DYING)
+ return NOTIFY_DONE;
+
if (!pr || acpi_bus_get_device(pr->handle, &device))
return NOTIFY_DONE;
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 7efe546a8c42..f775fa0d850f 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -84,7 +84,7 @@ EXPORT_SYMBOL_GPL(acpi_initialize_hp_context);
int acpi_scan_add_handler(struct acpi_scan_handler *handler)
{
- if (!handler || !handler->attach)
+ if (!handler)
return -EINVAL;
list_add_tail(&handler->list_node, &acpi_scan_handlers_list);
@@ -1551,9 +1551,13 @@ static void acpi_bus_get_power_flags(struct acpi_device *device)
*/
if (acpi_has_method(device->handle, "_PSC"))
device->power.flags.explicit_get = 1;
+
if (acpi_has_method(device->handle, "_IRC"))
device->power.flags.inrush_current = 1;
+ if (acpi_has_method(device->handle, "_DSW"))
+ device->power.flags.dsw_present = 1;
+
/*
* Enumerate supported power management states
*/
@@ -1793,8 +1797,10 @@ static void acpi_set_pnp_ids(acpi_handle handle, struct acpi_device_pnp *pnp,
return;
}
- if (info->valid & ACPI_VALID_HID)
+ if (info->valid & ACPI_VALID_HID) {
acpi_add_id(pnp, info->hardware_id.string);
+ pnp->type.platform_id = 1;
+ }
if (info->valid & ACPI_VALID_CID) {
cid_list = &info->compatible_id_list;
for (i = 0; i < cid_list->count; i++)
@@ -1973,6 +1979,9 @@ static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler,
{
const struct acpi_device_id *devid;
+ if (handler->match)
+ return handler->match(idstr, matchid);
+
for (devid = handler->ids; devid->id[0]; devid++)
if (!strcmp((char *)devid->id, idstr)) {
if (matchid)
@@ -2061,6 +2070,44 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
return AE_OK;
}
+static int acpi_check_spi_i2c_slave(struct acpi_resource *ares, void *data)
+{
+ bool *is_spi_i2c_slave_p = data;
+
+ if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
+ return 1;
+
+ /*
+ * devices that are connected to UART still need to be enumerated to
+ * platform bus
+ */
+ if (ares->data.common_serial_bus.type != ACPI_RESOURCE_SERIAL_TYPE_UART)
+ *is_spi_i2c_slave_p = true;
+
+ /* no need to do more checking */
+ return -1;
+}
+
+static void acpi_default_enumeration(struct acpi_device *device)
+{
+ struct list_head resource_list;
+ bool is_spi_i2c_slave = false;
+
+ if (!device->pnp.type.platform_id || device->handler)
+ return;
+
+ /*
+ * Do not enemerate SPI/I2C slaves as they will be enuerated by their
+ * respective parents.
+ */
+ INIT_LIST_HEAD(&resource_list);
+ acpi_dev_get_resources(device, &resource_list, acpi_check_spi_i2c_slave,
+ &is_spi_i2c_slave);
+ acpi_dev_free_resource_list(&resource_list);
+ if (!is_spi_i2c_slave)
+ acpi_create_platform_device(device);
+}
+
static int acpi_scan_attach_handler(struct acpi_device *device)
{
struct acpi_hardware_id *hwid;
@@ -2072,6 +2119,10 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
handler = acpi_scan_match_handler(hwid->id, &devid);
if (handler) {
+ if (!handler->attach) {
+ device->pnp.type.platform_id = 0;
+ continue;
+ }
device->handler = handler;
ret = handler->attach(device, devid);
if (ret > 0)
@@ -2082,6 +2133,9 @@ static int acpi_scan_attach_handler(struct acpi_device *device)
break;
}
}
+ if (!ret)
+ acpi_default_enumeration(device);
+
return ret;
}
@@ -2241,11 +2295,11 @@ int __init acpi_scan_init(void)
acpi_pci_root_init();
acpi_pci_link_init();
acpi_processor_init();
- acpi_platform_init();
acpi_lpss_init();
acpi_cmos_rtc_init();
acpi_container_init();
acpi_memory_hotplug_init();
+ acpi_pnp_init();
mutex_lock(&acpi_scan_lock);
/*
@@ -2259,12 +2313,16 @@ int __init acpi_scan_init(void)
if (result)
goto out;
- result = acpi_bus_scan_fixed();
- if (result) {
- acpi_detach_data(acpi_root->handle, acpi_scan_drop_device);
- acpi_device_del(acpi_root);
- put_device(&acpi_root->dev);
- goto out;
+ /* Fixed feature devices do not exist on HW-reduced platform */
+ if (!acpi_gbl_reduced_hardware) {
+ result = acpi_bus_scan_fixed();
+ if (result) {
+ acpi_detach_data(acpi_root->handle,
+ acpi_scan_drop_device);
+ acpi_device_del(acpi_root);
+ put_device(&acpi_root->dev);
+ goto out;
+ }
}
acpi_update_all_gpes();
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index c40fb2e81bbc..c11e3795431b 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -89,6 +89,7 @@ u32 acpi_target_system_state(void)
{
return acpi_target_sleep_state;
}
+EXPORT_SYMBOL_GPL(acpi_target_system_state);
static bool pwr_btn_event_pending;
@@ -611,6 +612,22 @@ static const struct platform_suspend_ops acpi_suspend_ops_old = {
.recover = acpi_pm_finish,
};
+static int acpi_freeze_begin(void)
+{
+ acpi_scan_lock_acquire();
+ return 0;
+}
+
+static void acpi_freeze_end(void)
+{
+ acpi_scan_lock_release();
+}
+
+static const struct platform_freeze_ops acpi_freeze_ops = {
+ .begin = acpi_freeze_begin,
+ .end = acpi_freeze_end,
+};
+
static void acpi_sleep_suspend_setup(void)
{
int i;
@@ -621,7 +638,9 @@ static void acpi_sleep_suspend_setup(void)
suspend_set_ops(old_suspend_ordering ?
&acpi_suspend_ops_old : &acpi_suspend_ops);
+ freeze_set_ops(&acpi_freeze_ops);
}
+
#else /* !CONFIG_SUSPEND */
static inline void acpi_sleep_suspend_setup(void) {}
#endif /* !CONFIG_SUSPEND */
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 21782290df41..05550ba44d32 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -44,6 +44,12 @@ static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
static int acpi_apic_instance __initdata;
+/*
+ * Disable table checksum verification for the early stage due to the size
+ * limitation of the current x86 early mapping implementation.
+ */
+static bool acpi_verify_table_checksum __initdata = false;
+
void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
{
if (!header)
@@ -333,6 +339,14 @@ int __init acpi_table_init(void)
{
acpi_status status;
+ if (acpi_verify_table_checksum) {
+ pr_info("Early table checksum verification enabled\n");
+ acpi_gbl_verify_table_checksum = TRUE;
+ } else {
+ pr_info("Early table checksum verification disabled\n");
+ acpi_gbl_verify_table_checksum = FALSE;
+ }
+
status = acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
if (ACPI_FAILURE(status))
return -EINVAL;
@@ -354,3 +368,12 @@ static int __init acpi_parse_apic_instance(char *str)
}
early_param("acpi_apic_instance", acpi_parse_apic_instance);
+
+static int __init acpi_force_table_verification_setup(char *s)
+{
+ acpi_verify_table_checksum = true;
+
+ return 0;
+}
+
+early_param("acpi_force_table_verification", acpi_force_table_verification_setup);
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 25bbc55dca89..112817e963e0 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -925,13 +925,10 @@ static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
if (result)
return result;
- status = acpi_attach_data(tz->device->handle,
- acpi_bus_private_data_handler,
- tz->thermal_zone);
- if (ACPI_FAILURE(status)) {
- pr_err(PREFIX "Error attaching device data\n");
+ status = acpi_bus_attach_private_data(tz->device->handle,
+ tz->thermal_zone);
+ if (ACPI_FAILURE(status))
return -ENODEV;
- }
tz->tz_enabled = 1;
@@ -946,7 +943,7 @@ static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
thermal_zone_device_unregister(tz->thermal_zone);
tz->thermal_zone = NULL;
- acpi_detach_data(tz->device->handle, acpi_bus_private_data_handler);
+ acpi_bus_detach_private_data(tz->device->handle);
}
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index bba526148583..07c8c5a5ee95 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -30,6 +30,7 @@
#include <linux/types.h>
#include <linux/hardirq.h>
#include <linux/acpi.h>
+#include <linux/dynamic_debug.h>
#include "internal.h"
@@ -457,6 +458,24 @@ acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code,
EXPORT_SYMBOL(acpi_evaluate_ost);
/**
+ * acpi_handle_path: Return the object path of handle
+ *
+ * Caller must free the returned buffer
+ */
+static char *acpi_handle_path(acpi_handle handle)
+{
+ struct acpi_buffer buffer = {
+ .length = ACPI_ALLOCATE_BUFFER,
+ .pointer = NULL
+ };
+
+ if (in_interrupt() ||
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer) != AE_OK)
+ return NULL;
+ return buffer.pointer;
+}
+
+/**
* acpi_handle_printk: Print message with ACPI prefix and object path
*
* This function is called through acpi_handle_<level> macros and prints
@@ -469,29 +488,50 @@ acpi_handle_printk(const char *level, acpi_handle handle, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
- struct acpi_buffer buffer = {
- .length = ACPI_ALLOCATE_BUFFER,
- .pointer = NULL
- };
const char *path;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
- if (in_interrupt() ||
- acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer) != AE_OK)
- path = "<n/a>";
- else
- path = buffer.pointer;
-
- printk("%sACPI: %s: %pV", level, path, &vaf);
+ path = acpi_handle_path(handle);
+ printk("%sACPI: %s: %pV", level, path ? path : "<n/a>" , &vaf);
va_end(args);
- kfree(buffer.pointer);
+ kfree(path);
}
EXPORT_SYMBOL(acpi_handle_printk);
+#if defined(CONFIG_DYNAMIC_DEBUG)
+/**
+ * __acpi_handle_debug: pr_debug with ACPI prefix and object path
+ *
+ * This function is called through acpi_handle_debug macro and debug
+ * prints a message with ACPI prefix and object path. This function
+ * acquires the global namespace mutex to obtain an object path. In
+ * interrupt context, it shows the object path as <n/a>.
+ */
+void
+__acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle,
+ const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list args;
+ const char *path;
+
+ va_start(args, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ path = acpi_handle_path(handle);
+ __dynamic_pr_debug(descriptor, "ACPI: %s: %pV", path ? path : "<n/a>", &vaf);
+
+ va_end(args);
+ kfree(path);
+}
+EXPORT_SYMBOL(__acpi_handle_debug);
+#endif
+
/**
* acpi_has_method: Check whether @handle has a method named @name
* @handle: ACPI device handle
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index f8bc5a755dda..101fb090dcb9 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -68,7 +68,7 @@ MODULE_AUTHOR("Bruno Ducrot");
MODULE_DESCRIPTION("ACPI Video Driver");
MODULE_LICENSE("GPL");
-static bool brightness_switch_enabled = 1;
+static bool brightness_switch_enabled;
module_param(brightness_switch_enabled, bool, 0644);
/*
@@ -150,6 +150,8 @@ struct acpi_video_enumerated_device {
struct acpi_video_bus {
struct acpi_device *device;
+ bool backlight_registered;
+ bool backlight_notifier_registered;
u8 dos_setting;
struct acpi_video_enumerated_device *attached_array;
u8 attached_count;
@@ -161,6 +163,7 @@ struct acpi_video_bus {
struct input_dev *input;
char phys[32]; /* for input device */
struct notifier_block pm_nb;
+ struct notifier_block backlight_nb;
};
struct acpi_video_device_flags {
@@ -473,6 +476,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
},
{
.callback = video_set_use_native_backlight,
+ .ident = "ThinkPad W530",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad W530"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
.ident = "ThinkPad X1 Carbon",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -488,6 +499,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
},
},
{
+ .callback = video_set_use_native_backlight,
+ .ident = "Lenovo Yoga 2 11",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Yoga 2 11"),
+ },
+ },
+ {
.callback = video_set_use_native_backlight,
.ident = "Thinkpad Helix",
.matches = {
@@ -521,6 +540,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
},
{
.callback = video_set_use_native_backlight,
+ .ident = "Acer Aspire V5-171",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "V5-171"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
.ident = "Acer Aspire V5-431",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@@ -528,6 +555,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
},
},
{
+ .callback = video_set_use_native_backlight,
+ .ident = "Acer Aspire V5-471G",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire V5-471G"),
+ },
+ },
+ {
.callback = video_set_use_native_backlight,
.ident = "HP ProBook 4340s",
.matches = {
@@ -579,6 +614,14 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
},
{
.callback = video_set_use_native_backlight,
+ .ident = "HP EliteBook 8470p",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8470p"),
+ },
+ },
+ {
+ .callback = video_set_use_native_backlight,
.ident = "HP EliteBook 8780w",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
@@ -1658,88 +1701,92 @@ acpi_video_bus_match(acpi_handle handle, u32 level, void *context,
static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
{
- if (acpi_video_verify_backlight_support()) {
- struct backlight_properties props;
- struct pci_dev *pdev;
- acpi_handle acpi_parent;
- struct device *parent = NULL;
- int result;
- static int count;
- char *name;
-
- result = acpi_video_init_brightness(device);
- if (result)
- return;
- name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
- if (!name)
- return;
- count++;
+ struct backlight_properties props;
+ struct pci_dev *pdev;
+ acpi_handle acpi_parent;
+ struct device *parent = NULL;
+ int result;
+ static int count;
+ char *name;
- acpi_get_parent(device->dev->handle, &acpi_parent);
+ result = acpi_video_init_brightness(device);
+ if (result)
+ return;
+ name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
+ if (!name)
+ return;
+ count++;
- pdev = acpi_get_pci_dev(acpi_parent);
- if (pdev) {
- parent = &pdev->dev;
- pci_dev_put(pdev);
- }
+ acpi_get_parent(device->dev->handle, &acpi_parent);
- memset(&props, 0, sizeof(struct backlight_properties));
- props.type = BACKLIGHT_FIRMWARE;
- props.max_brightness = device->brightness->count - 3;
- device->backlight = backlight_device_register(name,
- parent,
- device,
- &acpi_backlight_ops,
- &props);
- kfree(name);
- if (IS_ERR(device->backlight))
- return;
+ pdev = acpi_get_pci_dev(acpi_parent);
+ if (pdev) {
+ parent = &pdev->dev;
+ pci_dev_put(pdev);
+ }
- /*
- * Save current brightness level in case we have to restore it
- * before acpi_video_device_lcd_set_level() is called next time.
- */
- device->backlight->props.brightness =
- acpi_video_get_brightness(device->backlight);
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.type = BACKLIGHT_FIRMWARE;
+ props.max_brightness = device->brightness->count - 3;
+ device->backlight = backlight_device_register(name,
+ parent,
+ device,
+ &acpi_backlight_ops,
+ &props);
+ kfree(name);
+ if (IS_ERR(device->backlight))
+ return;
- device->cooling_dev = thermal_cooling_device_register("LCD",
- device->dev, &video_cooling_ops);
- if (IS_ERR(device->cooling_dev)) {
- /*
- * Set cooling_dev to NULL so we don't crash trying to
- * free it.
- * Also, why the hell we are returning early and
- * not attempt to register video output if cooling
- * device registration failed?
- * -- dtor
- */
- device->cooling_dev = NULL;
- return;
- }
+ /*
+ * Save current brightness level in case we have to restore it
+ * before acpi_video_device_lcd_set_level() is called next time.
+ */
+ device->backlight->props.brightness =
+ acpi_video_get_brightness(device->backlight);
- dev_info(&device->dev->dev, "registered as cooling_device%d\n",
- device->cooling_dev->id);
- result = sysfs_create_link(&device->dev->dev.kobj,
- &device->cooling_dev->device.kobj,
- "thermal_cooling");
- if (result)
- printk(KERN_ERR PREFIX "Create sysfs link\n");
- result = sysfs_create_link(&device->cooling_dev->device.kobj,
- &device->dev->dev.kobj, "device");
- if (result)
- printk(KERN_ERR PREFIX "Create sysfs link\n");
+ device->cooling_dev = thermal_cooling_device_register("LCD",
+ device->dev, &video_cooling_ops);
+ if (IS_ERR(device->cooling_dev)) {
+ /*
+ * Set cooling_dev to NULL so we don't crash trying to free it.
+ * Also, why the hell we are returning early and not attempt to
+ * register video output if cooling device registration failed?
+ * -- dtor
+ */
+ device->cooling_dev = NULL;
+ return;
}
+
+ dev_info(&device->dev->dev, "registered as cooling_device%d\n",
+ device->cooling_dev->id);
+ result = sysfs_create_link(&device->dev->dev.kobj,
+ &device->cooling_dev->device.kobj,
+ "thermal_cooling");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
+ result = sysfs_create_link(&device->cooling_dev->device.kobj,
+ &device->dev->dev.kobj, "device");
+ if (result)
+ printk(KERN_ERR PREFIX "Create sysfs link\n");
}
static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
{
struct acpi_video_device *dev;
+ if (video->backlight_registered)
+ return 0;
+
+ if (!acpi_video_verify_backlight_support())
+ return 0;
+
mutex_lock(&video->device_list_lock);
list_for_each_entry(dev, &video->video_device_list, entry)
acpi_video_dev_register_backlight(dev);
mutex_unlock(&video->device_list_lock);
+ video->backlight_registered = true;
+
video->pm_nb.notifier_call = acpi_video_resume;
video->pm_nb.priority = 0;
return register_pm_notifier(&video->pm_nb);
@@ -1767,13 +1814,20 @@ static void acpi_video_dev_unregister_backlight(struct acpi_video_device *device
static int acpi_video_bus_unregister_backlight(struct acpi_video_bus *video)
{
struct acpi_video_device *dev;
- int error = unregister_pm_notifier(&video->pm_nb);
+ int error;
+
+ if (!video->backlight_registered)
+ return 0;
+
+ error = unregister_pm_notifier(&video->pm_nb);
mutex_lock(&video->device_list_lock);
list_for_each_entry(dev, &video->video_device_list, entry)
acpi_video_dev_unregister_backlight(dev);
mutex_unlock(&video->device_list_lock);
+ video->backlight_registered = false;
+
return error;
}
@@ -1867,6 +1921,56 @@ static void acpi_video_bus_remove_notify_handler(struct acpi_video_bus *video)
video->input = NULL;
}
+static int acpi_video_backlight_notify(struct notifier_block *nb,
+ unsigned long val, void *bd)
+{
+ struct backlight_device *backlight = bd;
+ struct acpi_video_bus *video;
+
+ /* acpi_video_verify_backlight_support only cares about raw devices */
+ if (backlight->props.type != BACKLIGHT_RAW)
+ return NOTIFY_DONE;
+
+ video = container_of(nb, struct acpi_video_bus, backlight_nb);
+
+ switch (val) {
+ case BACKLIGHT_REGISTERED:
+ if (!acpi_video_verify_backlight_support())
+ acpi_video_bus_unregister_backlight(video);
+ break;
+ case BACKLIGHT_UNREGISTERED:
+ acpi_video_bus_register_backlight(video);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static int acpi_video_bus_add_backlight_notify_handler(
+ struct acpi_video_bus *video)
+{
+ int error;
+
+ video->backlight_nb.notifier_call = acpi_video_backlight_notify;
+ video->backlight_nb.priority = 0;
+ error = backlight_register_notifier(&video->backlight_nb);
+ if (error == 0)
+ video->backlight_notifier_registered = true;
+
+ return error;
+}
+
+static int acpi_video_bus_remove_backlight_notify_handler(
+ struct acpi_video_bus *video)
+{
+ if (!video->backlight_notifier_registered)
+ return 0;
+
+ video->backlight_notifier_registered = false;
+
+ return backlight_unregister_notifier(&video->backlight_nb);
+}
+
static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
{
struct acpi_video_device *dev, *next;
@@ -1948,6 +2052,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
acpi_video_bus_register_backlight(video);
acpi_video_bus_add_notify_handler(video);
+ acpi_video_bus_add_backlight_notify_handler(video);
return 0;
@@ -1971,6 +2076,7 @@ static int acpi_video_bus_remove(struct acpi_device *device)
video = acpi_driver_data(device);
+ acpi_video_bus_remove_backlight_notify_handler(video);
acpi_video_bus_remove_notify_handler(video);
acpi_video_bus_unregister_backlight(video);
acpi_video_bus_put_devices(video);
@@ -2061,6 +2167,20 @@ void acpi_video_unregister(void)
}
EXPORT_SYMBOL(acpi_video_unregister);
+void acpi_video_unregister_backlight(void)
+{
+ struct acpi_video_bus *video;
+
+ if (!register_count)
+ return;
+
+ mutex_lock(&video_list_lock);
+ list_for_each_entry(video, &video_bus_head, entry)
+ acpi_video_bus_unregister_backlight(video);
+ mutex_unlock(&video_list_lock);
+}
+EXPORT_SYMBOL(acpi_video_unregister_backlight);
+
/*
* This is kind of nasty. Hardware using Intel chipsets may require
* the video opregion code to be run first in order to initialise
diff --git a/drivers/base/dma-buf.c b/drivers/base/dma-buf.c
index ea77701deda4..840c7fa80983 100644
--- a/drivers/base/dma-buf.c
+++ b/drivers/base/dma-buf.c
@@ -491,7 +491,7 @@ EXPORT_SYMBOL_GPL(dma_buf_kunmap);
* dma-buf buffer.
*
* This function adjusts the passed in vma so that it points at the file of the
- * dma_buf operation. It alsog adjusts the starting pgoff and does bounds
+ * dma_buf operation. It also adjusts the starting pgoff and does bounds
* checking on the size of the vma. Then it calls the exporters mmap function to
* set up the mapping.
*
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 5b47210889e0..9e9227e1762d 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -131,9 +131,12 @@ EXPORT_SYMBOL_GPL(platform_get_resource_byname);
*/
int platform_get_irq_byname(struct platform_device *dev, const char *name)
{
- struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ,
- name);
+ struct resource *r;
+
+ if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node)
+ return of_irq_get_byname(dev->dev.of_node, name);
+ r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
return r ? r->start : -ENXIO;
}
EXPORT_SYMBOL_GPL(platform_get_irq_byname);
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 86d5e4fb5b98..343ffad59377 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -479,7 +479,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state, bool asyn
TRACE_DEVICE(dev);
TRACE_RESUME(0);
- if (dev->power.syscore)
+ if (dev->power.syscore || dev->power.direct_complete)
goto Out;
if (!dev->power.is_noirq_suspended)
@@ -605,7 +605,7 @@ static int device_resume_early(struct device *dev, pm_message_t state, bool asyn
TRACE_DEVICE(dev);
TRACE_RESUME(0);
- if (dev->power.syscore)
+ if (dev->power.syscore || dev->power.direct_complete)
goto Out;
if (!dev->power.is_late_suspended)
@@ -735,6 +735,12 @@ static int device_resume(struct device *dev, pm_message_t state, bool async)
if (dev->power.syscore)
goto Complete;
+ if (dev->power.direct_complete) {
+ /* Match the pm_runtime_disable() in __device_suspend(). */
+ pm_runtime_enable(dev);
+ goto Complete;
+ }
+
dpm_wait(dev->parent, async);
dpm_watchdog_set(&wd, dev);
device_lock(dev);
@@ -1007,7 +1013,7 @@ static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool a
goto Complete;
}
- if (dev->power.syscore)
+ if (dev->power.syscore || dev->power.direct_complete)
goto Complete;
dpm_wait_for_children(dev, async);
@@ -1146,7 +1152,7 @@ static int __device_suspend_late(struct device *dev, pm_message_t state, bool as
goto Complete;
}
- if (dev->power.syscore)
+ if (dev->power.syscore || dev->power.direct_complete)
goto Complete;
dpm_wait_for_children(dev, async);
@@ -1332,6 +1338,17 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
if (dev->power.syscore)
goto Complete;
+ if (dev->power.direct_complete) {
+ if (pm_runtime_status_suspended(dev)) {
+ pm_runtime_disable(dev);
+ if (pm_runtime_suspended_if_enabled(dev))
+ goto Complete;
+
+ pm_runtime_enable(dev);
+ }
+ dev->power.direct_complete = false;
+ }
+
dpm_watchdog_set(&wd, dev);
device_lock(dev);
@@ -1382,10 +1399,19 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
End:
if (!error) {
+ struct device *parent = dev->parent;
+
dev->power.is_suspended = true;
- if (dev->power.wakeup_path
- && dev->parent && !dev->parent->power.ignore_children)
- dev->parent->power.wakeup_path = true;
+ if (parent) {
+ spin_lock_irq(&parent->power.lock);
+
+ dev->parent->power.direct_complete = false;
+ if (dev->power.wakeup_path
+ && !dev->parent->power.ignore_children)
+ dev->parent->power.wakeup_path = true;
+
+ spin_unlock_irq(&parent->power.lock);
+ }
}
device_unlock(dev);
@@ -1487,7 +1513,7 @@ static int device_prepare(struct device *dev, pm_message_t state)
{
int (*callback)(struct device *) = NULL;
char *info = NULL;
- int error = 0;
+ int ret = 0;
if (dev->power.syscore)
return 0;
@@ -1523,17 +1549,27 @@ static int device_prepare(struct device *dev, pm_message_t state)
callback = dev->driver->pm->prepare;
}
- if (callback) {
- error = callback(dev);
- suspend_report_result(callback, error);
- }
+ if (callback)
+ ret = callback(dev);
device_unlock(dev);
- if (error)
+ if (ret < 0) {
+ suspend_report_result(callback, ret);
pm_runtime_put(dev);
-
- return error;
+ return ret;
+ }
+ /*
+ * A positive return value from ->prepare() means "this device appears
+ * to be runtime-suspended and its state is fine, so if it really is
+ * runtime-suspended, you can leave it in that state provided that you
+ * will do the same thing with all of its descendants". This only
+ * applies to suspend transitions, however.
+ */
+ spin_lock_irq(&dev->power.lock);
+ dev->power.direct_complete = ret > 0 && state.event == PM_EVENT_SUSPEND;
+ spin_unlock_irq(&dev->power.lock);
+ return 0;
}
/**
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index 25538675d59e..89ced955fafa 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -15,7 +15,6 @@
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/slab.h>
-#include <linux/cpufreq.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/rculist.h>
@@ -394,6 +393,13 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
* to keep the integrity of the internal data structures. Callers should ensure
* that this function is *NOT* called under RCU protection or in contexts where
* mutex cannot be locked.
+ *
+ * Return:
+ * 0: On success OR
+ * Duplicate OPPs (both freq and volt are same) and opp->available
+ * -EEXIST: Freq are same and volt are different OR
+ * Duplicate OPPs (both freq and volt are same) and !opp->available
+ * -ENOMEM: Memory allocation failure
*/
int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
{
@@ -443,15 +449,31 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
new_opp->u_volt = u_volt;
new_opp->available = true;
- /* Insert new OPP in order of increasing frequency */
+ /*
+ * Insert new OPP in order of increasing frequency
+ * and discard if already present
+ */
head = &dev_opp->opp_list;
list_for_each_entry_rcu(opp, &dev_opp->opp_list, node) {
- if (new_opp->rate < opp->rate)
+ if (new_opp->rate <= opp->rate)
break;
else
head = &opp->node;
}
+ /* Duplicate OPPs ? */
+ if (new_opp->rate == opp->rate) {
+ int ret = opp->available && new_opp->u_volt == opp->u_volt ?
+ 0 : -EEXIST;
+
+ dev_warn(dev, "%s: duplicate OPPs detected. Existing: freq: %lu, volt: %lu, enabled: %d. New: freq: %lu, volt: %lu, enabled: %d\n",
+ __func__, opp->rate, opp->u_volt, opp->available,
+ new_opp->rate, new_opp->u_volt, new_opp->available);
+ mutex_unlock(&dev_opp_list_lock);
+ kfree(new_opp);
+ return ret;
+ }
+
list_add_rcu(&new_opp->node, head);
mutex_unlock(&dev_opp_list_lock);
@@ -596,96 +618,6 @@ int dev_pm_opp_disable(struct device *dev, unsigned long freq)
}
EXPORT_SYMBOL_GPL(dev_pm_opp_disable);
-#ifdef CONFIG_CPU_FREQ
-/**
- * dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device
- * @dev: device for which we do this operation
- * @table: Cpufreq table returned back to caller
- *
- * Generate a cpufreq table for a provided device- this assumes that the
- * opp list is already initialized and ready for usage.
- *
- * This function allocates required memory for the cpufreq table. It is
- * expected that the caller does the required maintenance such as freeing
- * the table as required.
- *
- * Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM
- * if no memory available for the operation (table is not populated), returns 0
- * if successful and table is populated.
- *
- * WARNING: It is important for the callers to ensure refreshing their copy of
- * the table if any of the mentioned functions have been invoked in the interim.
- *
- * Locking: The internal device_opp and opp structures are RCU protected.
- * To simplify the logic, we pretend we are updater and hold relevant mutex here
- * Callers should ensure that this function is *NOT* called under RCU protection
- * or in contexts where mutex locking cannot be used.
- */
-int dev_pm_opp_init_cpufreq_table(struct device *dev,
- struct cpufreq_frequency_table **table)
-{
- struct device_opp *dev_opp;
- struct dev_pm_opp *opp;
- struct cpufreq_frequency_table *freq_table;
- int i = 0;
-
- /* Pretend as if I am an updater */
- mutex_lock(&dev_opp_list_lock);
-
- dev_opp = find_device_opp(dev);
- if (IS_ERR(dev_opp)) {
- int r = PTR_ERR(dev_opp);
- mutex_unlock(&dev_opp_list_lock);
- dev_err(dev, "%s: Device OPP not found (%d)\n", __func__, r);
- return r;
- }
-
- freq_table = kzalloc(sizeof(struct cpufreq_frequency_table) *
- (dev_pm_opp_get_opp_count(dev) + 1), GFP_KERNEL);
- if (!freq_table) {
- mutex_unlock(&dev_opp_list_lock);
- dev_warn(dev, "%s: Unable to allocate frequency table\n",
- __func__);
- return -ENOMEM;
- }
-
- list_for_each_entry(opp, &dev_opp->opp_list, node) {
- if (opp->available) {
- freq_table[i].driver_data = i;
- freq_table[i].frequency = opp->rate / 1000;
- i++;
- }
- }
- mutex_unlock(&dev_opp_list_lock);
-
- freq_table[i].driver_data = i;
- freq_table[i].frequency = CPUFREQ_TABLE_END;
-
- *table = &freq_table[0];
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table);
-
-/**
- * dev_pm_opp_free_cpufreq_table() - free the cpufreq table
- * @dev: device for which we do this operation
- * @table: table to free
- *
- * Free up the table allocated by dev_pm_opp_init_cpufreq_table
- */
-void dev_pm_opp_free_cpufreq_table(struct device *dev,
- struct cpufreq_frequency_table **table)
-{
- if (!table)
- return;
-
- kfree(*table);
- *table = NULL;
-}
-EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);
-#endif /* CONFIG_CPU_FREQ */
-
/**
* dev_pm_opp_get_notifier() - find notifier_head of the device with opp
* @dev: device pointer used to lookup device OPPs.
@@ -734,11 +666,9 @@ int of_init_opp_table(struct device *dev)
unsigned long freq = be32_to_cpup(val++) * 1000;
unsigned long volt = be32_to_cpup(val++);
- if (dev_pm_opp_add(dev, freq, volt)) {
+ if (dev_pm_opp_add(dev, freq, volt))
dev_warn(dev, "%s: Failed to add OPP %ld\n",
__func__, freq);
- continue;
- }
nr -= 2;
}
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 2d56f4113ae7..eb1bd2ecad8b 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -318,10 +318,16 @@ int device_init_wakeup(struct device *dev, bool enable)
{
int ret = 0;
+ if (!dev)
+ return -EINVAL;
+
if (enable) {
device_set_wakeup_capable(dev, true);
ret = device_wakeup_enable(dev);
} else {
+ if (dev->power.can_wakeup)
+ device_wakeup_disable(dev);
+
device_set_wakeup_capable(dev, false);
}
diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c
index b9a57fa4b710..565a9478cb94 100644
--- a/drivers/char/tpm/tpm_acpi.c
+++ b/drivers/char/tpm/tpm_acpi.c
@@ -95,7 +95,7 @@ int read_log(struct tpm_bios_log *log)
log->bios_event_log_end = log->bios_event_log + len;
- virt = acpi_os_map_memory(start, len);
+ virt = acpi_os_map_iomem(start, len);
if (!virt) {
kfree(log->bios_event_log);
printk("%s: ERROR - Unable to map memory\n", __func__);
@@ -104,6 +104,6 @@ int read_log(struct tpm_bios_log *log)
memcpy_fromio(log->bios_event_log, virt, len);
- acpi_os_unmap_memory(virt, len);
+ acpi_os_unmap_iomem(virt, len);
return 0;
}
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 17d7f13d19a5..50b2a7ebd747 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o
obj-$(CONFIG_COMMON_CLK) += clk-gate.o
obj-$(CONFIG_COMMON_CLK) += clk-mux.o
obj-$(CONFIG_COMMON_CLK) += clk-composite.o
+obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o
# hardware specific clock types
# please keep this section sorted lexicographically by file/directory path name
diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c
new file mode 100644
index 000000000000..ede685ca0d20
--- /dev/null
+++ b/drivers/clk/clk-fractional-divider.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Adjustable fractional divider clock implementation.
+ * Output rate = (m / n) * parent_rate.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/gcd.h>
+
+#define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw)
+
+static unsigned long clk_fd_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_fractional_divider *fd = to_clk_fd(hw);
+ unsigned long flags = 0;
+ u32 val, m, n;
+ u64 ret;
+
+ if (fd->lock)
+ spin_lock_irqsave(fd->lock, flags);
+
+ val = clk_readl(fd->reg);
+
+ if (fd->lock)
+ spin_unlock_irqrestore(fd->lock, flags);
+
+ m = (val & fd->mmask) >> fd->mshift;
+ n = (val & fd->nmask) >> fd->nshift;
+
+ ret = parent_rate * m;
+ do_div(ret, n);
+
+ return ret;
+}
+
+static long clk_fd_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_fractional_divider *fd = to_clk_fd(hw);
+ unsigned maxn = (fd->nmask >> fd->nshift) + 1;
+ unsigned div;
+
+ if (!rate || rate >= *prate)
+ return *prate;
+
+ div = gcd(*prate, rate);
+
+ while ((*prate / div) > maxn) {
+ div <<= 1;
+ rate <<= 1;
+ }
+
+ return rate;
+}
+
+static int clk_fd_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_fractional_divider *fd = to_clk_fd(hw);
+ unsigned long flags = 0;
+ unsigned long div;
+ unsigned n, m;
+ u32 val;
+
+ div = gcd(parent_rate, rate);
+ m = rate / div;
+ n = parent_rate / div;
+
+ if (fd->lock)
+ spin_lock_irqsave(fd->lock, flags);
+
+ val = clk_readl(fd->reg);
+ val &= ~(fd->mmask | fd->nmask);
+ val |= (m << fd->mshift) | (n << fd->nshift);
+ clk_writel(val, fd->reg);
+
+ if (fd->lock)
+ spin_unlock_irqrestore(fd->lock, flags);
+
+ return 0;
+}
+
+const struct clk_ops clk_fractional_divider_ops = {
+ .recalc_rate = clk_fd_recalc_rate,
+ .round_rate = clk_fd_round_rate,
+ .set_rate = clk_fd_set_rate,
+};
+EXPORT_SYMBOL_GPL(clk_fractional_divider_ops);
+
+struct clk *clk_register_fractional_divider(struct device *dev,
+ const char *name, const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth,
+ u8 clk_divider_flags, spinlock_t *lock)
+{
+ struct clk_fractional_divider *fd;
+ struct clk_init_data init;
+ struct clk *clk;
+
+ fd = kzalloc(sizeof(*fd), GFP_KERNEL);
+ if (!fd) {
+ dev_err(dev, "could not allocate fractional divider clk\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init.name = name;
+ init.ops = &clk_fractional_divider_ops;
+ init.flags = flags | CLK_IS_BASIC;
+ init.parent_names = parent_name ? &parent_name : NULL;
+ init.num_parents = parent_name ? 1 : 0;
+
+ fd->reg = reg;
+ fd->mshift = mshift;
+ fd->mmask = (BIT(mwidth) - 1) << mshift;
+ fd->nshift = nshift;
+ fd->nmask = (BIT(nwidth) - 1) << nshift;
+ fd->flags = clk_divider_flags;
+ fd->lock = lock;
+ fd->hw.init = &init;
+
+ clk = clk_register(dev, &fd->hw);
+ if (IS_ERR(clk))
+ kfree(fd);
+
+ return clk;
+}
+EXPORT_SYMBOL_GPL(clk_register_fractional_divider);
diff --git a/drivers/clk/rockchip/clk-rockchip.c b/drivers/clk/rockchip/clk-rockchip.c
index 967c141b1a20..4cf838d52ef6 100644
--- a/drivers/clk/rockchip/clk-rockchip.c
+++ b/drivers/clk/rockchip/clk-rockchip.c
@@ -24,8 +24,7 @@ static DEFINE_SPINLOCK(clk_lock);
* Gate clocks
*/
-static void __init rk2928_gate_clk_init(struct device_node *node,
- void *data)
+static void __init rk2928_gate_clk_init(struct device_node *node)
{
struct clk_onecell_data *clk_data;
const char *clk_parent;
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index bd7dc733c1ca..9eddf22d56a4 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -1278,8 +1278,7 @@ static void __init of_sunxi_table_clock_setup(const struct of_device_id *clk_mat
const struct of_device_id *match;
void (*setup_function)(struct device_node *, const void *) = function;
- for_each_matching_node(np, clk_match) {
- match = of_match_node(clk_match, np);
+ for_each_matching_node_and_match(np, clk_match, &match) {
data = match->data;
setup_function(np, data);
}
@@ -1310,7 +1309,7 @@ static void __init sunxi_clock_protect(void)
}
}
-static void __init sunxi_init_clocks(void)
+static void __init sunxi_init_clocks(struct device_node *np)
{
/* Register factor clocks */
of_sunxi_table_clock_setup(clk_factors_match, sunxi_factors_clk_setup);
diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c
index 3e2999d11d15..58734817d502 100644
--- a/drivers/clk/ti/gate.c
+++ b/drivers/clk/ti/gate.c
@@ -221,7 +221,7 @@ static void __init of_ti_gate_clk_setup(struct device_node *node)
{
_of_ti_gate_clk_setup(node, &omap_gate_clk_ops, NULL);
}
-CLK_OF_DECLARE(ti_gate_clk, "ti,gate-clock", of_ti_gate_clk_setup)
+CLK_OF_DECLARE(ti_gate_clk, "ti,gate-clock", of_ti_gate_clk_setup);
static void __init of_ti_wait_gate_clk_setup(struct device_node *node)
{
diff --git a/drivers/clocksource/clksrc-of.c b/drivers/clocksource/clksrc-of.c
index ae2e4278c42a..0093a8e49e14 100644
--- a/drivers/clocksource/clksrc-of.c
+++ b/drivers/clocksource/clksrc-of.c
@@ -27,7 +27,7 @@ void __init clocksource_of_init(void)
{
struct device_node *np;
const struct of_device_id *match;
- clocksource_of_init_fn init_func;
+ of_init_fn_1 init_func;
unsigned clocksources = 0;
for_each_matching_node_and_match(np, __clksrc_of_table, &match) {
diff --git a/drivers/clocksource/versatile.c b/drivers/clocksource/versatile.c
index e4c50ad2f9d9..2798e7492234 100644
--- a/drivers/clocksource/versatile.c
+++ b/drivers/clocksource/versatile.c
@@ -20,7 +20,7 @@
static void __iomem *versatile_sys_24mhz;
-static u32 notrace versatile_sys_24mhz_read(void)
+static u64 notrace versatile_sys_24mhz_read(void)
{
return readl(versatile_sys_24mhz);
}
@@ -34,7 +34,7 @@ static void __init versatile_sched_clock_init(struct device_node *node)
versatile_sys_24mhz = base + SYS_24MHZ;
- setup_sched_clock(versatile_sys_24mhz_read, 32, 24000000);
+ sched_clock_register(versatile_sys_24mhz_read, 32, 24000000);
}
CLOCKSOURCE_OF_DECLARE(versatile, "arm,vexpress-sysreg",
- versatile_sched_clock_init);
+ versatile_sched_clock_init);
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index d2c7b4b8ffd5..36d20d0fce27 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -5,7 +5,8 @@
# big LITTLE core layer and glue drivers
config ARM_BIG_LITTLE_CPUFREQ
tristate "Generic ARM big LITTLE CPUfreq driver"
- depends on ARM && BIG_LITTLE && ARM_CPU_TOPOLOGY && HAVE_CLK
+ depends on (BIG_LITTLE && ARM_CPU_TOPOLOGY) || (ARM64 && SMP)
+ depends on HAVE_CLK
select PM_OPP
help
This enables the Generic CPUfreq driver for ARM big.LITTLE platforms.
@@ -85,7 +86,7 @@ config ARM_EXYNOS_CPU_FREQ_BOOST_SW
It allows usage of special frequencies for Samsung Exynos
processors if thermal conditions are appropriate.
- It reguires, for safe operation, thermal framework with properly
+ It requires, for safe operation, thermal framework with properly
defined trip points.
If in doubt, say N.
@@ -186,7 +187,7 @@ config ARM_S3C2416_CPUFREQ
S3C2450 SoC. The S3C2416 supports changing the rate of the
armdiv clock source and also entering a so called dynamic
voltage scaling mode in which it is possible to reduce the
- core voltage of the cpu.
+ core voltage of the CPU.
If in doubt, say N.
diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
index d369349eeaab..89ae88f91895 100644
--- a/drivers/cpufreq/Kconfig.x86
+++ b/drivers/cpufreq/Kconfig.x86
@@ -10,7 +10,7 @@ config X86_INTEL_PSTATE
The driver implements an internal governor and will become
the scaling driver and governor for Sandy bridge processors.
- When this driver is enabled it will become the perferred
+ When this driver is enabled it will become the preferred
scaling driver for Sandy bridge processors.
If in doubt, say N.
@@ -52,7 +52,7 @@ config X86_ACPI_CPUFREQ_CPB
help
The powernow-k8 driver used to provide a sysfs knob called "cpb"
to disable the Core Performance Boosting feature of AMD CPUs. This
- file has now been superseeded by the more generic "boost" entry.
+ file has now been superseded by the more generic "boost" entry.
By enabling this option the acpi_cpufreq driver provides the old
entry in addition to the new boost ones, for compatibility reasons.
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 0dbb963c1aef..738c8b7b17dc 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -1,5 +1,7 @@
# CPUfreq core
obj-$(CONFIG_CPU_FREQ) += cpufreq.o freq_table.o
+obj-$(CONFIG_PM_OPP) += cpufreq_opp.o
+
# CPUfreq stats
obj-$(CONFIG_CPU_FREQ_STAT) += cpufreq_stats.o
diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c
index 000e4e0afd7e..b0c18ed8d83f 100644
--- a/drivers/cpufreq/acpi-cpufreq.c
+++ b/drivers/cpufreq/acpi-cpufreq.c
@@ -213,7 +213,7 @@ static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data)
static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
{
- int i;
+ struct cpufreq_frequency_table *pos;
struct acpi_processor_performance *perf;
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
@@ -223,10 +223,9 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data)
perf = data->acpi_data;
- for (i = 0; data->freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
- if (msr == perf->states[data->freq_table[i].driver_data].status)
- return data->freq_table[i].frequency;
- }
+ cpufreq_for_each_entry(pos, data->freq_table)
+ if (msr == perf->states[pos->driver_data].status)
+ return pos->frequency;
return data->freq_table[0].frequency;
}
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
index bad2ed317ba2..1f4d4e315057 100644
--- a/drivers/cpufreq/arm_big_little.c
+++ b/drivers/cpufreq/arm_big_little.c
@@ -226,22 +226,22 @@ static inline u32 get_table_count(struct cpufreq_frequency_table *table)
/* get the minimum frequency in the cpufreq_frequency_table */
static inline u32 get_table_min(struct cpufreq_frequency_table *table)
{
- int i;
+ struct cpufreq_frequency_table *pos;
uint32_t min_freq = ~0;
- for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++)
- if (table[i].frequency < min_freq)
- min_freq = table[i].frequency;
+ cpufreq_for_each_entry(pos, table)
+ if (pos->frequency < min_freq)
+ min_freq = pos->frequency;
return min_freq;
}
/* get the maximum frequency in the cpufreq_frequency_table */
static inline u32 get_table_max(struct cpufreq_frequency_table *table)
{
- int i;
+ struct cpufreq_frequency_table *pos;
uint32_t max_freq = 0;
- for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++)
- if (table[i].frequency > max_freq)
- max_freq = table[i].frequency;
+ cpufreq_for_each_entry(pos, table)
+ if (pos->frequency > max_freq)
+ max_freq = pos->frequency;
return max_freq;
}
diff --git a/drivers/cpufreq/cpufreq-nforce2.c b/drivers/cpufreq/cpufreq-nforce2.c
index bc447b9003c3..a2258090b58b 100644
--- a/drivers/cpufreq/cpufreq-nforce2.c
+++ b/drivers/cpufreq/cpufreq-nforce2.c
@@ -379,7 +379,7 @@ static struct cpufreq_driver nforce2_driver = {
};
#ifdef MODULE
-static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = {
+static const struct pci_device_id nforce2_ids[] = {
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2 },
{}
};
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index abda6609d3e7..ae11dd51f81d 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -354,6 +354,18 @@ static void cpufreq_notify_post_transition(struct cpufreq_policy *policy,
void cpufreq_freq_transition_begin(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs)
{
+
+ /*
+ * Catch double invocations of _begin() which lead to self-deadlock.
+ * ASYNC_NOTIFICATION drivers are left out because the cpufreq core
+ * doesn't invoke _begin() on their behalf, and hence the chances of
+ * double invocations are very low. Moreover, there are scenarios
+ * where these checks can emit false-positive warnings in these
+ * drivers; so we avoid that by skipping them altogether.
+ */
+ WARN_ON(!(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION)
+ && current == policy->transition_task);
+
wait:
wait_event(policy->transition_wait, !policy->transition_ongoing);
@@ -365,6 +377,7 @@ wait:
}
policy->transition_ongoing = true;
+ policy->transition_task = current;
spin_unlock(&policy->transition_lock);
@@ -381,6 +394,7 @@ void cpufreq_freq_transition_end(struct cpufreq_policy *policy,
cpufreq_notify_post_transition(policy, freqs, transition_failed);
policy->transition_ongoing = false;
+ policy->transition_task = NULL;
wake_up(&policy->transition_wait);
}
@@ -1802,12 +1816,43 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
* GOVERNORS *
*********************************************************************/
+static int __target_index(struct cpufreq_policy *policy,
+ struct cpufreq_frequency_table *freq_table, int index)
+{
+ struct cpufreq_freqs freqs;
+ int retval = -EINVAL;
+ bool notify;
+
+ notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION);
+
+ if (notify) {
+ freqs.old = policy->cur;
+ freqs.new = freq_table[index].frequency;
+ freqs.flags = 0;
+
+ pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
+ __func__, policy->cpu, freqs.old, freqs.new);
+
+ cpufreq_freq_transition_begin(policy, &freqs);
+ }
+
+ retval = cpufreq_driver->target_index(policy, index);
+ if (retval)
+ pr_err("%s: Failed to change cpu frequency: %d\n", __func__,
+ retval);
+
+ if (notify)
+ cpufreq_freq_transition_end(policy, &freqs, retval);
+
+ return retval;
+}
+
int __cpufreq_driver_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
- int retval = -EINVAL;
unsigned int old_target_freq = target_freq;
+ int retval = -EINVAL;
if (cpufreq_disabled())
return -ENODEV;
@@ -1834,8 +1879,6 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
retval = cpufreq_driver->target(policy, target_freq, relation);
else if (cpufreq_driver->target_index) {
struct cpufreq_frequency_table *freq_table;
- struct cpufreq_freqs freqs;
- bool notify;
int index;
freq_table = cpufreq_frequency_get_table(policy->cpu);
@@ -1856,26 +1899,7 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy,
goto out;
}
- notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION);
-
- if (notify) {
- freqs.old = policy->cur;
- freqs.new = freq_table[index].frequency;
- freqs.flags = 0;
-
- pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
- __func__, policy->cpu, freqs.old, freqs.new);
-
- cpufreq_freq_transition_begin(policy, &freqs);
- }
-
- retval = cpufreq_driver->target_index(policy, index);
- if (retval)
- pr_err("%s: Failed to change cpu frequency: %d\n",
- __func__, retval);
-
- if (notify)
- cpufreq_freq_transition_end(policy, &freqs, retval);
+ retval = __target_index(policy, freq_table, index);
}
out:
diff --git a/drivers/cpufreq/cpufreq_opp.c b/drivers/cpufreq/cpufreq_opp.c
new file mode 100644
index 000000000000..c0c6f4a4eccf
--- /dev/null
+++ b/drivers/cpufreq/cpufreq_opp.c
@@ -0,0 +1,110 @@
+/*
+ * Generic OPP helper interface for CPUFreq drivers
+ *
+ * Copyright (C) 2009-2014 Texas Instruments Incorporated.
+ * Nishanth Menon
+ * Romit Dasgupta
+ * Kevin Hilman
+ *
+ * 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.
+ */
+#include <linux/cpufreq.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/pm_opp.h>
+#include <linux/rcupdate.h>
+#include <linux/slab.h>
+
+/**
+ * dev_pm_opp_init_cpufreq_table() - create a cpufreq table for a device
+ * @dev: device for which we do this operation
+ * @table: Cpufreq table returned back to caller
+ *
+ * Generate a cpufreq table for a provided device- this assumes that the
+ * opp list is already initialized and ready for usage.
+ *
+ * This function allocates required memory for the cpufreq table. It is
+ * expected that the caller does the required maintenance such as freeing
+ * the table as required.
+ *
+ * Returns -EINVAL for bad pointers, -ENODEV if the device is not found, -ENOMEM
+ * if no memory available for the operation (table is not populated), returns 0
+ * if successful and table is populated.
+ *
+ * WARNING: It is important for the callers to ensure refreshing their copy of
+ * the table if any of the mentioned functions have been invoked in the interim.
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * Since we just use the regular accessor functions to access the internal data
+ * structures, we use RCU read lock inside this function. As a result, users of
+ * this function DONOT need to use explicit locks for invoking.
+ */
+int dev_pm_opp_init_cpufreq_table(struct device *dev,
+ struct cpufreq_frequency_table **table)
+{
+ struct dev_pm_opp *opp;
+ struct cpufreq_frequency_table *freq_table = NULL;
+ int i, max_opps, ret = 0;
+ unsigned long rate;
+
+ rcu_read_lock();
+
+ max_opps = dev_pm_opp_get_opp_count(dev);
+ if (max_opps <= 0) {
+ ret = max_opps ? max_opps : -ENODATA;
+ goto out;
+ }
+
+ freq_table = kzalloc(sizeof(*freq_table) * (max_opps + 1), GFP_KERNEL);
+ if (!freq_table) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0, rate = 0; i < max_opps; i++, rate++) {
+ /* find next rate */
+ opp = dev_pm_opp_find_freq_ceil(dev, &rate);
+ if (IS_ERR(opp)) {
+ ret = PTR_ERR(opp);
+ goto out;
+ }
+ freq_table[i].driver_data = i;
+ freq_table[i].frequency = rate / 1000;
+ }
+
+ freq_table[i].driver_data = i;
+ freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+ *table = &freq_table[0];
+
+out:
+ rcu_read_unlock();
+ if (ret)
+ kfree(freq_table);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_init_cpufreq_table);
+
+/**
+ * dev_pm_opp_free_cpufreq_table() - free the cpufreq table
+ * @dev: device for which we do this operation
+ * @table: table to free
+ *
+ * Free up the table allocated by dev_pm_opp_init_cpufreq_table
+ */
+void dev_pm_opp_free_cpufreq_table(struct device *dev,
+ struct cpufreq_frequency_table **table)
+{
+ if (!table)
+ return;
+
+ kfree(*table);
+ *table = NULL;
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_free_cpufreq_table);
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index ecaaebf969fc..0cd9b4dcef99 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -182,11 +182,11 @@ static void cpufreq_stats_free_table(unsigned int cpu)
static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
{
- unsigned int i, j, count = 0, ret = 0;
+ unsigned int i, count = 0, ret = 0;
struct cpufreq_stats *stat;
unsigned int alloc_size;
unsigned int cpu = policy->cpu;
- struct cpufreq_frequency_table *table;
+ struct cpufreq_frequency_table *pos, *table;
table = cpufreq_frequency_get_table(cpu);
if (unlikely(!table))
@@ -205,12 +205,8 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
stat->cpu = cpu;
per_cpu(cpufreq_stats_table, cpu) = stat;
- for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
- unsigned int freq = table[i].frequency;
- if (freq == CPUFREQ_ENTRY_INVALID)
- continue;
+ cpufreq_for_each_valid_entry(pos, table)
count++;
- }
alloc_size = count * sizeof(int) + count * sizeof(u64);
@@ -228,15 +224,11 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
stat->trans_table = stat->freq_table + count;
#endif
- j = 0;
- for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
- unsigned int freq = table[i].frequency;
- if (freq == CPUFREQ_ENTRY_INVALID)
- continue;
- if (freq_table_get_index(stat, freq) == -1)
- stat->freq_table[j++] = freq;
- }
- stat->state_num = j;
+ i = 0;
+ cpufreq_for_each_valid_entry(pos, table)
+ if (freq_table_get_index(stat, pos->frequency) == -1)
+ stat->freq_table[i++] = pos->frequency;
+ stat->state_num = i;
spin_lock(&cpufreq_stats_lock);
stat->last_time = get_jiffies_64();
stat->last_index = freq_table_get_index(stat, policy->cur);
diff --git a/drivers/cpufreq/dbx500-cpufreq.c b/drivers/cpufreq/dbx500-cpufreq.c
index 412a78bb0c94..4bebc1b5db48 100644
--- a/drivers/cpufreq/dbx500-cpufreq.c
+++ b/drivers/cpufreq/dbx500-cpufreq.c
@@ -45,7 +45,7 @@ static struct cpufreq_driver dbx500_cpufreq_driver = {
static int dbx500_cpufreq_probe(struct platform_device *pdev)
{
- int i = 0;
+ struct cpufreq_frequency_table *pos;
freq_table = dev_get_platdata(&pdev->dev);
if (!freq_table) {
@@ -60,10 +60,8 @@ static int dbx500_cpufreq_probe(struct platform_device *pdev)
}
pr_info("dbx500-cpufreq: Available frequencies:\n");
- while (freq_table[i].frequency != CPUFREQ_TABLE_END) {
- pr_info(" %d Mhz\n", freq_table[i].frequency/1000);
- i++;
- }
+ cpufreq_for_each_entry(pos, freq_table)
+ pr_info(" %d Mhz\n", pos->frequency / 1000);
return cpufreq_register_driver(&dbx500_cpufreq_driver);
}
diff --git a/drivers/cpufreq/elanfreq.c b/drivers/cpufreq/elanfreq.c
index 7f5d2a68c353..1c06e786c9ba 100644
--- a/drivers/cpufreq/elanfreq.c
+++ b/drivers/cpufreq/elanfreq.c
@@ -147,7 +147,7 @@ static int elanfreq_target(struct cpufreq_policy *policy,
static int elanfreq_cpu_init(struct cpufreq_policy *policy)
{
struct cpuinfo_x86 *c = &cpu_data(0);
- unsigned int i;
+ struct cpufreq_frequency_table *pos;
/* capability check */
if ((c->x86_vendor != X86_VENDOR_AMD) ||
@@ -159,10 +159,9 @@ static int elanfreq_cpu_init(struct cpufreq_policy *policy)
max_freq = elanfreq_get_cpu_frequency(0);
/* table init */
- for (i = 0; (elanfreq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
- if (elanfreq_table[i].frequency > max_freq)
- elanfreq_table[i].frequency = CPUFREQ_ENTRY_INVALID;
- }
+ cpufreq_for_each_entry(pos, elanfreq_table)
+ if (pos->frequency > max_freq)
+ pos->frequency = CPUFREQ_ENTRY_INVALID;
/* cpuinfo and default policy values */
policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index 348c8bafe436..1e0ec57bf6e3 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -28,17 +28,16 @@ static unsigned int locking_frequency;
static int exynos_cpufreq_get_index(unsigned int freq)
{
struct cpufreq_frequency_table *freq_table = exynos_info->freq_table;
- int index;
+ struct cpufreq_frequency_table *pos;
- for (index = 0;
- freq_table[index].frequency != CPUFREQ_TABLE_END; index++)
- if (freq_table[index].frequency == freq)
+ cpufreq_for_each_entry(pos, freq_table)
+ if (pos->frequency == freq)
break;
- if (freq_table[index].frequency == CPUFREQ_TABLE_END)
+ if (pos->frequency == CPUFREQ_TABLE_END)
return -EINVAL;
- return index;
+ return pos - freq_table;
}
static int exynos_cpufreq_scale(unsigned int target_freq)
@@ -48,6 +47,7 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
struct cpufreq_policy *policy = cpufreq_cpu_get(0);
unsigned int arm_volt, safe_arm_volt = 0;
unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz;
+ struct device *dev = exynos_info->dev;
unsigned int old_freq;
int index, old_index;
int ret = 0;
@@ -89,8 +89,8 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
/* Firstly, voltage up to increase frequency */
ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
if (ret) {
- pr_err("%s: failed to set cpu voltage to %d\n",
- __func__, arm_volt);
+ dev_err(dev, "failed to set cpu voltage to %d\n",
+ arm_volt);
return ret;
}
}
@@ -99,8 +99,8 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
ret = regulator_set_voltage(arm_regulator, safe_arm_volt,
safe_arm_volt);
if (ret) {
- pr_err("%s: failed to set cpu voltage to %d\n",
- __func__, safe_arm_volt);
+ dev_err(dev, "failed to set cpu voltage to %d\n",
+ safe_arm_volt);
return ret;
}
}
@@ -114,8 +114,8 @@ static int exynos_cpufreq_scale(unsigned int target_freq)
ret = regulator_set_voltage(arm_regulator, arm_volt,
arm_volt);
if (ret) {
- pr_err("%s: failed to set cpu voltage to %d\n",
- __func__, arm_volt);
+ dev_err(dev, "failed to set cpu voltage to %d\n",
+ arm_volt);
goto out;
}
}
@@ -162,6 +162,8 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
if (!exynos_info)
return -ENOMEM;
+ exynos_info->dev = &pdev->dev;
+
if (of_machine_is_compatible("samsung,exynos4210")) {
exynos_info->type = EXYNOS_SOC_4210;
ret = exynos4210_cpufreq_init(exynos_info);
@@ -183,13 +185,13 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
goto err_vdd_arm;
if (exynos_info->set_freq == NULL) {
- pr_err("%s: No set_freq function (ERR)\n", __func__);
+ dev_err(&pdev->dev, "No set_freq function (ERR)\n");
goto err_vdd_arm;
}
arm_regulator = regulator_get(NULL, "vdd_arm");
if (IS_ERR(arm_regulator)) {
- pr_err("%s: failed to get resource vdd_arm\n", __func__);
+ dev_err(&pdev->dev, "failed to get resource vdd_arm\n");
goto err_vdd_arm;
}
@@ -199,7 +201,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
if (!cpufreq_register_driver(&exynos_driver))
return 0;
- pr_err("%s: failed to register cpufreq driver\n", __func__);
+ dev_err(&pdev->dev, "failed to register cpufreq driver\n");
regulator_put(arm_regulator);
err_vdd_arm:
kfree(exynos_info);
diff --git a/drivers/cpufreq/exynos-cpufreq.h b/drivers/cpufreq/exynos-cpufreq.h
index 51af42e1b7fe..9f2062a7cc02 100644
--- a/drivers/cpufreq/exynos-cpufreq.h
+++ b/drivers/cpufreq/exynos-cpufreq.h
@@ -42,6 +42,7 @@ struct apll_freq {
struct exynos_dvfs_info {
enum exynos_soc_type type;
+ struct device *dev;
unsigned long mpll_freq_khz;
unsigned int pll_safe_idx;
struct clk *cpu_clk;
diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c
index a6b8214d7b77..f33f25b483ca 100644
--- a/drivers/cpufreq/exynos5440-cpufreq.c
+++ b/drivers/cpufreq/exynos5440-cpufreq.c
@@ -114,25 +114,23 @@ static struct cpufreq_freqs freqs;
static int init_div_table(void)
{
- struct cpufreq_frequency_table *freq_tbl = dvfs_info->freq_table;
+ struct cpufreq_frequency_table *pos, *freq_tbl = dvfs_info->freq_table;
unsigned int tmp, clk_div, ema_div, freq, volt_id;
- int i = 0;
struct dev_pm_opp *opp;
rcu_read_lock();
- for (i = 0; freq_tbl[i].frequency != CPUFREQ_TABLE_END; i++) {
-
+ cpufreq_for_each_entry(pos, freq_tbl) {
opp = dev_pm_opp_find_freq_exact(dvfs_info->dev,
- freq_tbl[i].frequency * 1000, true);
+ pos->frequency * 1000, true);
if (IS_ERR(opp)) {
rcu_read_unlock();
dev_err(dvfs_info->dev,
"failed to find valid OPP for %u KHZ\n",
- freq_tbl[i].frequency);
+ pos->frequency);
return PTR_ERR(opp);
}
- freq = freq_tbl[i].frequency / 1000; /* In MHZ */
+ freq = pos->frequency / 1000; /* In MHZ */
clk_div = ((freq / CPU_DIV_FREQ_MAX) & P0_7_CPUCLKDEV_MASK)
<< P0_7_CPUCLKDEV_SHIFT;
clk_div |= ((freq / CPU_ATB_FREQ_MAX) & P0_7_ATBCLKDEV_MASK)
@@ -157,7 +155,8 @@ static int init_div_table(void)
tmp = (clk_div | ema_div | (volt_id << P0_7_VDD_SHIFT)
| ((freq / FREQ_UNIT) << P0_7_FREQ_SHIFT));
- __raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 * i);
+ __raw_writel(tmp, dvfs_info->base + XMU_PMU_P0_7 + 4 *
+ (pos - freq_tbl));
}
rcu_read_unlock();
@@ -166,8 +165,9 @@ static int init_div_table(void)
static void exynos_enable_dvfs(unsigned int cur_frequency)
{
- unsigned int tmp, i, cpu;
+ unsigned int tmp, cpu;
struct cpufreq_frequency_table *freq_table = dvfs_info->freq_table;
+ struct cpufreq_frequency_table *pos;
/* Disable DVFS */
__raw_writel(0, dvfs_info->base + XMU_DVFS_CTRL);
@@ -182,15 +182,15 @@ static void exynos_enable_dvfs(unsigned int cur_frequency)
__raw_writel(tmp, dvfs_info->base + XMU_PMUIRQEN);
/* Set initial performance index */
- for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++)
- if (freq_table[i].frequency == cur_frequency)
+ cpufreq_for_each_entry(pos, freq_table)
+ if (pos->frequency == cur_frequency)
break;
- if (freq_table[i].frequency == CPUFREQ_TABLE_END) {
+ if (pos->frequency == CPUFREQ_TABLE_END) {
dev_crit(dvfs_info->dev, "Boot up frequency not supported\n");
/* Assign the highest frequency */
- i = 0;
- cur_frequency = freq_table[i].frequency;
+ pos = freq_table;
+ cur_frequency = pos->frequency;
}
dev_info(dvfs_info->dev, "Setting dvfs initial frequency = %uKHZ",
@@ -199,7 +199,7 @@ static void exynos_enable_dvfs(unsigned int cur_frequency)
for (cpu = 0; cpu < CONFIG_NR_CPUS; cpu++) {
tmp = __raw_readl(dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
tmp &= ~(P_VALUE_MASK << C0_3_PSTATE_NEW_SHIFT);
- tmp |= (i << C0_3_PSTATE_NEW_SHIFT);
+ tmp |= ((pos - freq_table) << C0_3_PSTATE_NEW_SHIFT);
__raw_writel(tmp, dvfs_info->base + XMU_C0_3_PSTATE + cpu * 4);
}
diff --git a/drivers/cpufreq/freq_table.c b/drivers/cpufreq/freq_table.c
index 08e7bbcf6d73..1632981c4b25 100644
--- a/drivers/cpufreq/freq_table.c
+++ b/drivers/cpufreq/freq_table.c
@@ -21,22 +21,19 @@
int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table)
{
+ struct cpufreq_frequency_table *pos;
unsigned int min_freq = ~0;
unsigned int max_freq = 0;
- unsigned int i;
+ unsigned int freq;
- for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
- unsigned int freq = table[i].frequency;
- if (freq == CPUFREQ_ENTRY_INVALID) {
- pr_debug("table entry %u is invalid, skipping\n", i);
+ cpufreq_for_each_valid_entry(pos, table) {
+ freq = pos->frequency;
- continue;
- }
if (!cpufreq_boost_enabled()
- && (table[i].flags & CPUFREQ_BOOST_FREQ))
+ && (pos->flags & CPUFREQ_BOOST_FREQ))
continue;
- pr_debug("table entry %u: %u kHz\n", i, freq);
+ pr_debug("table entry %u: %u kHz\n", (int)(pos - table), freq);
if (freq < min_freq)
min_freq = freq;
if (freq > max_freq)
@@ -57,7 +54,8 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
struct cpufreq_frequency_table *table)
{
- unsigned int next_larger = ~0, freq, i = 0;
+ struct cpufreq_frequency_table *pos;
+ unsigned int freq, next_larger = ~0;
bool found = false;
pr_debug("request for verification of policy (%u - %u kHz) for cpu %u\n",
@@ -65,9 +63,9 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
cpufreq_verify_within_cpu_limits(policy);
- for (; freq = table[i].frequency, freq != CPUFREQ_TABLE_END; i++) {
- if (freq == CPUFREQ_ENTRY_INVALID)
- continue;
+ cpufreq_for_each_valid_entry(pos, table) {
+ freq = pos->frequency;
+
if ((freq >= policy->min) && (freq <= policy->max)) {
found = true;
break;
@@ -118,7 +116,8 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
.driver_data = ~0,
.frequency = 0,
};
- unsigned int i;
+ struct cpufreq_frequency_table *pos;
+ unsigned int freq, i = 0;
pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
target_freq, relation, policy->cpu);
@@ -132,15 +131,19 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
break;
}
- for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
- unsigned int freq = table[i].frequency;
- if (freq == CPUFREQ_ENTRY_INVALID)
- continue;
+ cpufreq_for_each_valid_entry(pos, table) {
+ freq = pos->frequency;
+
+ i = pos - table;
if ((freq < policy->min) || (freq > policy->max))
continue;
+ if (freq == target_freq) {
+ optimal.driver_data = i;
+ break;
+ }
switch (relation) {
case CPUFREQ_RELATION_H:
- if (freq <= target_freq) {
+ if (freq < target_freq) {
if (freq >= optimal.frequency) {
optimal.frequency = freq;
optimal.driver_data = i;
@@ -153,7 +156,7 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
}
break;
case CPUFREQ_RELATION_L:
- if (freq >= target_freq) {
+ if (freq > target_freq) {
if (freq <= optimal.frequency) {
optimal.frequency = freq;
optimal.driver_data = i;
@@ -184,8 +187,7 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
unsigned int freq)
{
- struct cpufreq_frequency_table *table;
- int i;
+ struct cpufreq_frequency_table *pos, *table;
table = cpufreq_frequency_get_table(policy->cpu);
if (unlikely(!table)) {
@@ -193,10 +195,9 @@ int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
return -ENOENT;
}
- for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
- if (table[i].frequency == freq)
- return i;
- }
+ cpufreq_for_each_valid_entry(pos, table)
+ if (pos->frequency == freq)
+ return pos - table;
return -EINVAL;
}
@@ -208,16 +209,13 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_get_index);
static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
bool show_boost)
{
- unsigned int i = 0;
ssize_t count = 0;
- struct cpufreq_frequency_table *table = policy->freq_table;
+ struct cpufreq_frequency_table *pos, *table = policy->freq_table;
if (!table)
return -ENODEV;
- for (i = 0; (table[i].frequency != CPUFREQ_TABLE_END); i++) {
- if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
- continue;
+ cpufreq_for_each_valid_entry(pos, table) {
/*
* show_boost = true and driver_data = BOOST freq
* display BOOST freqs
@@ -229,10 +227,10 @@ static ssize_t show_available_freqs(struct cpufreq_policy *policy, char *buf,
* show_boost = false and driver_data != BOOST freq
* display NON BOOST freqs
*/
- if (show_boost ^ (table[i].flags & CPUFREQ_BOOST_FREQ))
+ if (show_boost ^ (pos->flags & CPUFREQ_BOOST_FREQ))
continue;
- count += sprintf(&buf[count], "%d ", table[i].frequency);
+ count += sprintf(&buf[count], "%d ", pos->frequency);
}
count += sprintf(&buf[count], "\n");
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index e27fca86fe4f..af366c21d4b4 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -9,7 +9,6 @@
#include <linux/clk.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
-#include <linux/delay.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/of.h>
@@ -170,25 +169,25 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
return -ENOENT;
}
- arm_clk = devm_clk_get(cpu_dev, "arm");
- pll1_sys_clk = devm_clk_get(cpu_dev, "pll1_sys");
- pll1_sw_clk = devm_clk_get(cpu_dev, "pll1_sw");
- step_clk = devm_clk_get(cpu_dev, "step");
- pll2_pfd2_396m_clk = devm_clk_get(cpu_dev, "pll2_pfd2_396m");
+ arm_clk = clk_get(cpu_dev, "arm");
+ pll1_sys_clk = clk_get(cpu_dev, "pll1_sys");
+ pll1_sw_clk = clk_get(cpu_dev, "pll1_sw");
+ step_clk = clk_get(cpu_dev, "step");
+ pll2_pfd2_396m_clk = clk_get(cpu_dev, "pll2_pfd2_396m");
if (IS_ERR(arm_clk) || IS_ERR(pll1_sys_clk) || IS_ERR(pll1_sw_clk) ||
IS_ERR(step_clk) || IS_ERR(pll2_pfd2_396m_clk)) {
dev_err(cpu_dev, "failed to get clocks\n");
ret = -ENOENT;
- goto put_node;
+ goto put_clk;
}
- arm_reg = devm_regulator_get(cpu_dev, "arm");
- pu_reg = devm_regulator_get(cpu_dev, "pu");
- soc_reg = devm_regulator_get(cpu_dev, "soc");
+ arm_reg = regulator_get(cpu_dev, "arm");
+ pu_reg = regulator_get(cpu_dev, "pu");
+ soc_reg = regulator_get(cpu_dev, "soc");
if (IS_ERR(arm_reg) || IS_ERR(pu_reg) || IS_ERR(soc_reg)) {
dev_err(cpu_dev, "failed to get regulators\n");
ret = -ENOENT;
- goto put_node;
+ goto put_reg;
}
/*
@@ -201,21 +200,21 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
ret = of_init_opp_table(cpu_dev);
if (ret < 0) {
dev_err(cpu_dev, "failed to init OPP table: %d\n", ret);
- goto put_node;
+ goto put_reg;
}
num = dev_pm_opp_get_opp_count(cpu_dev);
if (num < 0) {
ret = num;
dev_err(cpu_dev, "no OPP table is found: %d\n", ret);
- goto put_node;
+ goto put_reg;
}
}
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
if (ret) {
dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
- goto put_node;
+ goto put_reg;
}
/* Make imx6_soc_volt array's size same as arm opp number */
@@ -301,7 +300,24 @@ soc_opp_out:
free_freq_table:
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
-put_node:
+put_reg:
+ if (!IS_ERR(arm_reg))
+ regulator_put(arm_reg);
+ if (!IS_ERR(pu_reg))
+ regulator_put(pu_reg);
+ if (!IS_ERR(soc_reg))
+ regulator_put(soc_reg);
+put_clk:
+ if (!IS_ERR(arm_clk))
+ clk_put(arm_clk);
+ if (!IS_ERR(pll1_sys_clk))
+ clk_put(pll1_sys_clk);
+ if (!IS_ERR(pll1_sw_clk))
+ clk_put(pll1_sw_clk);
+ if (!IS_ERR(step_clk))
+ clk_put(step_clk);
+ if (!IS_ERR(pll2_pfd2_396m_clk))
+ clk_put(pll2_pfd2_396m_clk);
of_node_put(np);
return ret;
}
@@ -310,6 +326,14 @@ static int imx6q_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&imx6q_cpufreq_driver);
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
+ regulator_put(arm_reg);
+ regulator_put(pu_reg);
+ regulator_put(soc_reg);
+ clk_put(arm_clk);
+ clk_put(pll1_sys_clk);
+ clk_put(pll1_sw_clk);
+ clk_put(step_clk);
+ clk_put(pll2_pfd2_396m_clk);
return 0;
}
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index eab8ccfe6beb..aebd4572eb6d 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -32,18 +32,16 @@
#include <asm/msr.h>
#include <asm/cpu_device_id.h>
-#define SAMPLE_COUNT 3
-
#define BYT_RATIOS 0x66a
#define BYT_VIDS 0x66b
#define BYT_TURBO_RATIOS 0x66c
#define BYT_TURBO_VIDS 0x66d
-#define FRAC_BITS 6
+#define FRAC_BITS 8
#define int_tofp(X) ((int64_t)(X) << FRAC_BITS)
#define fp_toint(X) ((X) >> FRAC_BITS)
-#define FP_ROUNDUP(X) ((X) += 1 << FRAC_BITS)
+
static inline int32_t mul_fp(int32_t x, int32_t y)
{
@@ -59,8 +57,8 @@ struct sample {
int32_t core_pct_busy;
u64 aperf;
u64 mperf;
- unsigned long long tsc;
int freq;
+ ktime_t time;
};
struct pstate_data {
@@ -90,17 +88,15 @@ struct _pid {
struct cpudata {
int cpu;
- char name[64];
-
struct timer_list timer;
struct pstate_data pstate;
struct vid_data vid;
struct _pid pid;
+ ktime_t last_sample_time;
u64 prev_aperf;
u64 prev_mperf;
- unsigned long long prev_tsc;
struct sample sample;
};
@@ -200,7 +196,10 @@ static signed int pid_calc(struct _pid *pid, int32_t busy)
pid->last_err = fp_error;
result = pterm + mul_fp(pid->integral, pid->i_gain) + dterm;
-
+ if (result >= 0)
+ result = result + (1 << (FRAC_BITS-1));
+ else
+ result = result - (1 << (FRAC_BITS-1));
return (signed int)fp_toint(result);
}
@@ -546,8 +545,6 @@ static inline void intel_pstate_pstate_decrease(struct cpudata *cpu, int steps)
static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
{
- sprintf(cpu->name, "Intel 2nd generation core");
-
cpu->pstate.min_pstate = pstate_funcs.get_min();
cpu->pstate.max_pstate = pstate_funcs.get_max();
cpu->pstate.turbo_pstate = pstate_funcs.get_turbo();
@@ -557,50 +554,45 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
}
-static inline void intel_pstate_calc_busy(struct cpudata *cpu,
- struct sample *sample)
+static inline void intel_pstate_calc_busy(struct cpudata *cpu)
{
- int32_t core_pct;
- int32_t c0_pct;
+ struct sample *sample = &cpu->sample;
+ int64_t core_pct;
+ int32_t rem;
- core_pct = div_fp(int_tofp((sample->aperf)),
- int_tofp((sample->mperf)));
- core_pct = mul_fp(core_pct, int_tofp(100));
- FP_ROUNDUP(core_pct);
+ core_pct = int_tofp(sample->aperf) * int_tofp(100);
+ core_pct = div_u64_rem(core_pct, int_tofp(sample->mperf), &rem);
- c0_pct = div_fp(int_tofp(sample->mperf), int_tofp(sample->tsc));
+ if ((rem << 1) >= int_tofp(sample->mperf))
+ core_pct += 1;
sample->freq = fp_toint(
mul_fp(int_tofp(cpu->pstate.max_pstate * 1000), core_pct));
- sample->core_pct_busy = mul_fp(core_pct, c0_pct);
+ sample->core_pct_busy = (int32_t)core_pct;
}
static inline void intel_pstate_sample(struct cpudata *cpu)
{
u64 aperf, mperf;
- unsigned long long tsc;
rdmsrl(MSR_IA32_APERF, aperf);
rdmsrl(MSR_IA32_MPERF, mperf);
- tsc = native_read_tsc();
aperf = aperf >> FRAC_BITS;
mperf = mperf >> FRAC_BITS;
- tsc = tsc >> FRAC_BITS;
+ cpu->last_sample_time = cpu->sample.time;
+ cpu->sample.time = ktime_get();
cpu->sample.aperf = aperf;
cpu->sample.mperf = mperf;
- cpu->sample.tsc = tsc;
cpu->sample.aperf -= cpu->prev_aperf;
cpu->sample.mperf -= cpu->prev_mperf;
- cpu->sample.tsc -= cpu->prev_tsc;
- intel_pstate_calc_busy(cpu, &cpu->sample);
+ intel_pstate_calc_busy(cpu);
cpu->prev_aperf = aperf;
cpu->prev_mperf = mperf;
- cpu->prev_tsc = tsc;
}
static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
@@ -614,13 +606,25 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
{
- int32_t core_busy, max_pstate, current_pstate;
+ int32_t core_busy, max_pstate, current_pstate, sample_ratio;
+ u32 duration_us;
+ u32 sample_time;
core_busy = cpu->sample.core_pct_busy;
max_pstate = int_tofp(cpu->pstate.max_pstate);
current_pstate = int_tofp(cpu->pstate.current_pstate);
core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate));
- return FP_ROUNDUP(core_busy);
+
+ sample_time = (pid_params.sample_rate_ms * USEC_PER_MSEC);
+ duration_us = (u32) ktime_us_delta(cpu->sample.time,
+ cpu->last_sample_time);
+ if (duration_us > sample_time * 3) {
+ sample_ratio = div_fp(int_tofp(sample_time),
+ int_tofp(duration_us));
+ core_busy = mul_fp(core_busy, sample_ratio);
+ }
+
+ return core_busy;
}
static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
@@ -674,10 +678,13 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
ICPU(0x37, byt_params),
ICPU(0x3a, core_params),
ICPU(0x3c, core_params),
+ ICPU(0x3d, core_params),
ICPU(0x3e, core_params),
ICPU(0x3f, core_params),
ICPU(0x45, core_params),
ICPU(0x46, core_params),
+ ICPU(0x4f, core_params),
+ ICPU(0x56, core_params),
{}
};
MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);
diff --git a/drivers/cpufreq/longhaul.c b/drivers/cpufreq/longhaul.c
index 5c4369b5d834..c913906a719e 100644
--- a/drivers/cpufreq/longhaul.c
+++ b/drivers/cpufreq/longhaul.c
@@ -530,6 +530,7 @@ static int longhaul_get_ranges(void)
static void longhaul_setup_voltagescaling(void)
{
+ struct cpufreq_frequency_table *freq_pos;
union msr_longhaul longhaul;
struct mV_pos minvid, maxvid, vid;
unsigned int j, speed, pos, kHz_step, numvscales;
@@ -608,18 +609,16 @@ static void longhaul_setup_voltagescaling(void)
/* Calculate kHz for one voltage step */
kHz_step = (highest_speed - min_vid_speed) / numvscales;
- j = 0;
- while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
- speed = longhaul_table[j].frequency;
+ cpufreq_for_each_entry(freq_pos, longhaul_table) {
+ speed = freq_pos->frequency;
if (speed > min_vid_speed)
pos = (speed - min_vid_speed) / kHz_step + minvid.pos;
else
pos = minvid.pos;
- longhaul_table[j].driver_data |= mV_vrm_table[pos] << 8;
+ freq_pos->driver_data |= mV_vrm_table[pos] << 8;
vid = vrm_mV_table[mV_vrm_table[pos]];
printk(KERN_INFO PFX "f: %d kHz, index: %d, vid: %d mV\n",
- speed, j, vid.mV);
- j++;
+ speed, (int)(freq_pos - longhaul_table), vid.mV);
}
can_scale_voltage = 1;
diff --git a/drivers/cpufreq/pasemi-cpufreq.c b/drivers/cpufreq/pasemi-cpufreq.c
index 84c84b5f0f3a..35dd4d7ffee0 100644
--- a/drivers/cpufreq/pasemi-cpufreq.c
+++ b/drivers/cpufreq/pasemi-cpufreq.c
@@ -136,9 +136,10 @@ void restore_astate(int cpu)
static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
+ struct cpufreq_frequency_table *pos;
const u32 *max_freqp;
u32 max_freq;
- int i, cur_astate;
+ int cur_astate;
struct resource res;
struct device_node *cpu, *dn;
int err = -ENODEV;
@@ -197,10 +198,9 @@ static int pas_cpufreq_cpu_init(struct cpufreq_policy *policy)
pr_debug("initializing frequency table\n");
/* initialize frequency table */
- for (i=0; pas_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
- pas_freqs[i].frequency =
- get_astate_freq(pas_freqs[i].driver_data) * 100000;
- pr_debug("%d: %d\n", i, pas_freqs[i].frequency);
+ cpufreq_for_each_entry(pos, pas_freqs) {
+ pos->frequency = get_astate_freq(pos->driver_data) * 100000;
+ pr_debug("%d: %d\n", (int)(pos - pas_freqs), pos->frequency);
}
cur_astate = get_cur_astate(policy->cpu);
diff --git a/drivers/cpufreq/powernow-k6.c b/drivers/cpufreq/powernow-k6.c
index 78904e6ca4a0..c8012bc86910 100644
--- a/drivers/cpufreq/powernow-k6.c
+++ b/drivers/cpufreq/powernow-k6.c
@@ -151,6 +151,7 @@ static int powernow_k6_target(struct cpufreq_policy *policy,
static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
{
+ struct cpufreq_frequency_table *pos;
unsigned int i, f;
unsigned khz;
@@ -168,12 +169,11 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy)
}
}
if (param_max_multiplier) {
- for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
- if (clock_ratio[i].driver_data == param_max_multiplier) {
+ cpufreq_for_each_entry(pos, clock_ratio)
+ if (pos->driver_data == param_max_multiplier) {
max_multiplier = param_max_multiplier;
goto have_max_multiplier;
}
- }
printk(KERN_ERR "powernow-k6: invalid max_multiplier parameter, valid parameters 20, 30, 35, 40, 45, 50, 55, 60\n");
return -EINVAL;
}
@@ -201,12 +201,12 @@ have_busfreq:
param_busfreq = busfreq * 10;
/* table init */
- for (i = 0; (clock_ratio[i].frequency != CPUFREQ_TABLE_END); i++) {
- f = clock_ratio[i].driver_data;
+ cpufreq_for_each_entry(pos, clock_ratio) {
+ f = pos->driver_data;
if (f > max_multiplier)
- clock_ratio[i].frequency = CPUFREQ_ENTRY_INVALID;
+ pos->frequency = CPUFREQ_ENTRY_INVALID;
else
- clock_ratio[i].frequency = busfreq * f;
+ pos->frequency = busfreq * f;
}
/* cpuinfo and default policy values */
diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c
index 1b6ae6b57c11..f9ce7e4bf0fe 100644
--- a/drivers/cpufreq/powernow-k8.c
+++ b/drivers/cpufreq/powernow-k8.c
@@ -27,6 +27,8 @@
* power and thermal data sheets, (e.g. 30417.pdf, 30430.pdf, 43375.pdf)
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/module.h>
@@ -45,7 +47,6 @@
#include <linux/mutex.h>
#include <acpi/processor.h>
-#define PFX "powernow-k8: "
#define VERSION "version 2.20.00"
#include "powernow-k8.h"
@@ -161,7 +162,7 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
u32 i = 0;
if ((fid & INVALID_FID_MASK) || (data->currvid & INVALID_VID_MASK)) {
- printk(KERN_ERR PFX "internal error - overflow on fid write\n");
+ pr_err("internal error - overflow on fid write\n");
return 1;
}
@@ -175,9 +176,7 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
do {
wrmsr(MSR_FIDVID_CTL, lo, data->plllock * PLL_LOCK_CONVERSION);
if (i++ > 100) {
- printk(KERN_ERR PFX
- "Hardware error - pending bit very stuck - "
- "no further pstate changes possible\n");
+ pr_err("Hardware error - pending bit very stuck - no further pstate changes possible\n");
return 1;
}
} while (query_current_values_with_pending_wait(data));
@@ -185,15 +184,13 @@ static int write_new_fid(struct powernow_k8_data *data, u32 fid)
count_off_irt(data);
if (savevid != data->currvid) {
- printk(KERN_ERR PFX
- "vid change on fid trans, old 0x%x, new 0x%x\n",
- savevid, data->currvid);
+ pr_err("vid change on fid trans, old 0x%x, new 0x%x\n",
+ savevid, data->currvid);
return 1;
}
if (fid != data->currfid) {
- printk(KERN_ERR PFX
- "fid trans failed, fid 0x%x, curr 0x%x\n", fid,
+ pr_err("fid trans failed, fid 0x%x, curr 0x%x\n", fid,
data->currfid);
return 1;
}
@@ -209,7 +206,7 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid)
int i = 0;
if ((data->currfid & INVALID_FID_MASK) || (vid & INVALID_VID_MASK)) {
- printk(KERN_ERR PFX "internal error - overflow on vid write\n");
+ pr_err("internal error - overflow on vid write\n");
return 1;
}
@@ -223,23 +220,19 @@ static int write_new_vid(struct powernow_k8_data *data, u32 vid)
do {
wrmsr(MSR_FIDVID_CTL, lo, STOP_GRANT_5NS);
if (i++ > 100) {
- printk(KERN_ERR PFX "internal error - pending bit "
- "very stuck - no further pstate "
- "changes possible\n");
+ pr_err("internal error - pending bit very stuck - no further pstate changes possible\n");
return 1;
}
} while (query_current_values_with_pending_wait(data));
if (savefid != data->currfid) {
- printk(KERN_ERR PFX "fid changed on vid trans, old "
- "0x%x new 0x%x\n",
- savefid, data->currfid);
+ pr_err("fid changed on vid trans, old 0x%x new 0x%x\n",
+ savefid, data->currfid);
return 1;
}
if (vid != data->currvid) {
- printk(KERN_ERR PFX "vid trans failed, vid 0x%x, "
- "curr 0x%x\n",
+ pr_err("vid trans failed, vid 0x%x, curr 0x%x\n",
vid, data->currvid);
return 1;
}
@@ -283,8 +276,7 @@ static int transition_fid_vid(struct powernow_k8_data *data,
return 1;
if ((reqfid != data->currfid) || (reqvid != data->currvid)) {
- printk(KERN_ERR PFX "failed (cpu%d): req 0x%x 0x%x, "
- "curr 0x%x 0x%x\n",
+ pr_err("failed (cpu%d): req 0x%x 0x%x, curr 0x%x 0x%x\n",
smp_processor_id(),
reqfid, reqvid, data->currfid, data->currvid);
return 1;
@@ -304,8 +296,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data,
u32 savefid = data->currfid;
u32 maxvid, lo, rvomult = 1;
- pr_debug("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, "
- "reqvid 0x%x, rvo 0x%x\n",
+ pr_debug("ph1 (cpu%d): start, currfid 0x%x, currvid 0x%x, reqvid 0x%x, rvo 0x%x\n",
smp_processor_id(),
data->currfid, data->currvid, reqvid, data->rvo);
@@ -342,8 +333,7 @@ static int core_voltage_pre_transition(struct powernow_k8_data *data,
return 1;
if (savefid != data->currfid) {
- printk(KERN_ERR PFX "ph1 err, currfid changed 0x%x\n",
- data->currfid);
+ pr_err("ph1 err, currfid changed 0x%x\n", data->currfid);
return 1;
}
@@ -360,13 +350,11 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
u32 fid_interval, savevid = data->currvid;
if (data->currfid == reqfid) {
- printk(KERN_ERR PFX "ph2 null fid transition 0x%x\n",
- data->currfid);
+ pr_err("ph2 null fid transition 0x%x\n", data->currfid);
return 0;
}
- pr_debug("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, "
- "reqfid 0x%x\n",
+ pr_debug("ph2 (cpu%d): starting, currfid 0x%x, currvid 0x%x, reqfid 0x%x\n",
smp_processor_id(),
data->currfid, data->currvid, reqfid);
@@ -409,15 +397,13 @@ static int core_frequency_transition(struct powernow_k8_data *data, u32 reqfid)
return 1;
if (data->currfid != reqfid) {
- printk(KERN_ERR PFX
- "ph2: mismatch, failed fid transition, "
- "curr 0x%x, req 0x%x\n",
+ pr_err("ph2: mismatch, failed fid transition, curr 0x%x, req 0x%x\n",
data->currfid, reqfid);
return 1;
}
if (savevid != data->currvid) {
- printk(KERN_ERR PFX "ph2: vid changed, save 0x%x, curr 0x%x\n",
+ pr_err("ph2: vid changed, save 0x%x, curr 0x%x\n",
savevid, data->currvid);
return 1;
}
@@ -444,17 +430,14 @@ static int core_voltage_post_transition(struct powernow_k8_data *data,
return 1;
if (savefid != data->currfid) {
- printk(KERN_ERR PFX
- "ph3: bad fid change, save 0x%x, curr 0x%x\n",
- savefid, data->currfid);
+ pr_err("ph3: bad fid change, save 0x%x, curr 0x%x\n",
+ savefid, data->currfid);
return 1;
}
if (data->currvid != reqvid) {
- printk(KERN_ERR PFX
- "ph3: failed vid transition\n, "
- "req 0x%x, curr 0x%x",
- reqvid, data->currvid);
+ pr_err("ph3: failed vid transition\n, req 0x%x, curr 0x%x",
+ reqvid, data->currvid);
return 1;
}
}
@@ -498,23 +481,20 @@ static void check_supported_cpu(void *_rc)
if ((eax & CPUID_XFAM) == CPUID_XFAM_K8) {
if (((eax & CPUID_USE_XFAM_XMOD) != CPUID_USE_XFAM_XMOD) ||
((eax & CPUID_XMOD) > CPUID_XMOD_REV_MASK)) {
- printk(KERN_INFO PFX
- "Processor cpuid %x not supported\n", eax);
+ pr_info("Processor cpuid %x not supported\n", eax);
return;
}
eax = cpuid_eax(CPUID_GET_MAX_CAPABILITIES);
if (eax < CPUID_FREQ_VOLT_CAPABILITIES) {
- printk(KERN_INFO PFX
- "No frequency change capabilities detected\n");
+ pr_info("No frequency change capabilities detected\n");
return;
}
cpuid(CPUID_FREQ_VOLT_CAPABILITIES, &eax, &ebx, &ecx, &edx);
if ((edx & P_STATE_TRANSITION_CAPABLE)
!= P_STATE_TRANSITION_CAPABLE) {
- printk(KERN_INFO PFX
- "Power state transitions not supported\n");
+ pr_info("Power state transitions not supported\n");
return;
}
*rc = 0;
@@ -529,43 +509,39 @@ static int check_pst_table(struct powernow_k8_data *data, struct pst_s *pst,
for (j = 0; j < data->numps; j++) {
if (pst[j].vid > LEAST_VID) {
- printk(KERN_ERR FW_BUG PFX "vid %d invalid : 0x%x\n",
- j, pst[j].vid);
+ pr_err(FW_BUG "vid %d invalid : 0x%x\n", j,
+ pst[j].vid);
return -EINVAL;
}
if (pst[j].vid < data->rvo) {
/* vid + rvo >= 0 */
- printk(KERN_ERR FW_BUG PFX "0 vid exceeded with pstate"
- " %d\n", j);
+ pr_err(FW_BUG "0 vid exceeded with pstate %d\n", j);
return -ENODEV;
}
if (pst[j].vid < maxvid + data->rvo) {
/* vid + rvo >= maxvid */
- printk(KERN_ERR FW_BUG PFX "maxvid exceeded with pstate"
- " %d\n", j);
+ pr_err(FW_BUG "maxvid exceeded with pstate %d\n", j);
return -ENODEV;
}
if (pst[j].fid > MAX_FID) {
- printk(KERN_ERR FW_BUG PFX "maxfid exceeded with pstate"
- " %d\n", j);
+ pr_err(FW_BUG "maxfid exceeded with pstate %d\n", j);
return -ENODEV;
}
if (j && (pst[j].fid < HI_FID_TABLE_BOTTOM)) {
/* Only first fid is allowed to be in "low" range */
- printk(KERN_ERR FW_BUG PFX "two low fids - %d : "
- "0x%x\n", j, pst[j].fid);
+ pr_err(FW_BUG "two low fids - %d : 0x%x\n", j,
+ pst[j].fid);
return -EINVAL;
}
if (pst[j].fid < lastfid)
lastfid = pst[j].fid;
}
if (lastfid & 1) {
- printk(KERN_ERR FW_BUG PFX "lastfid invalid\n");
+ pr_err(FW_BUG "lastfid invalid\n");
return -EINVAL;
}
if (lastfid > LO_FID_TABLE_TOP)
- printk(KERN_INFO FW_BUG PFX
- "first fid not from lo freq table\n");
+ pr_info(FW_BUG "first fid not from lo freq table\n");
return 0;
}
@@ -582,16 +558,14 @@ static void print_basics(struct powernow_k8_data *data)
for (j = 0; j < data->numps; j++) {
if (data->powernow_table[j].frequency !=
CPUFREQ_ENTRY_INVALID) {
- printk(KERN_INFO PFX
- "fid 0x%x (%d MHz), vid 0x%x\n",
- data->powernow_table[j].driver_data & 0xff,
- data->powernow_table[j].frequency/1000,
- data->powernow_table[j].driver_data >> 8);
+ pr_info("fid 0x%x (%d MHz), vid 0x%x\n",
+ data->powernow_table[j].driver_data & 0xff,
+ data->powernow_table[j].frequency/1000,
+ data->powernow_table[j].driver_data >> 8);
}
}
if (data->batps)
- printk(KERN_INFO PFX "Only %d pstates on battery\n",
- data->batps);
+ pr_info("Only %d pstates on battery\n", data->batps);
}
static int fill_powernow_table(struct powernow_k8_data *data,
@@ -602,21 +576,20 @@ static int fill_powernow_table(struct powernow_k8_data *data,
if (data->batps) {
/* use ACPI support to get full speed on mains power */
- printk(KERN_WARNING PFX
- "Only %d pstates usable (use ACPI driver for full "
- "range\n", data->batps);
+ pr_warn("Only %d pstates usable (use ACPI driver for full range\n",
+ data->batps);
data->numps = data->batps;
}
for (j = 1; j < data->numps; j++) {
if (pst[j-1].fid >= pst[j].fid) {
- printk(KERN_ERR PFX "PST out of sequence\n");
+ pr_err("PST out of sequence\n");
return -EINVAL;
}
}
if (data->numps < 2) {
- printk(KERN_ERR PFX "no p states to transition\n");
+ pr_err("no p states to transition\n");
return -ENODEV;
}
@@ -626,7 +599,7 @@ static int fill_powernow_table(struct powernow_k8_data *data,
powernow_table = kzalloc((sizeof(*powernow_table)
* (data->numps + 1)), GFP_KERNEL);
if (!powernow_table) {
- printk(KERN_ERR PFX "powernow_table memory alloc failure\n");
+ pr_err("powernow_table memory alloc failure\n");
return -ENOMEM;
}
@@ -681,13 +654,13 @@ static int find_psb_table(struct powernow_k8_data *data)
pr_debug("table vers: 0x%x\n", psb->tableversion);
if (psb->tableversion != PSB_VERSION_1_4) {
- printk(KERN_ERR FW_BUG PFX "PSB table is not v1.4\n");
+ pr_err(FW_BUG "PSB table is not v1.4\n");
return -ENODEV;
}
pr_debug("flags: 0x%x\n", psb->flags1);
if (psb->flags1) {
- printk(KERN_ERR FW_BUG PFX "unknown flags\n");
+ pr_err(FW_BUG "unknown flags\n");
return -ENODEV;
}
@@ -716,7 +689,7 @@ static int find_psb_table(struct powernow_k8_data *data)
cpst = 1;
}
if (cpst != 1) {
- printk(KERN_ERR FW_BUG PFX "numpst must be 1\n");
+ pr_err(FW_BUG "numpst must be 1\n");
return -ENODEV;
}
@@ -742,9 +715,8 @@ static int find_psb_table(struct powernow_k8_data *data)
* BIOS and Kernel Developer's Guide, which is available on
* www.amd.com
*/
- printk(KERN_ERR FW_BUG PFX "No PSB or ACPI _PSS objects\n");
- printk(KERN_ERR PFX "Make sure that your BIOS is up to date"
- " and Cool'N'Quiet support is enabled in BIOS setup\n");
+ pr_err(FW_BUG "No PSB or ACPI _PSS objects\n");
+ pr_err("Make sure that your BIOS is up to date and Cool'N'Quiet support is enabled in BIOS setup\n");
return -ENODEV;
}
@@ -819,8 +791,7 @@ static int powernow_k8_cpu_init_acpi(struct powernow_k8_data *data)
acpi_processor_notify_smm(THIS_MODULE);
if (!zalloc_cpumask_var(&data->acpi_data.shared_cpu_map, GFP_KERNEL)) {
- printk(KERN_ERR PFX
- "unable to alloc powernow_k8_data cpumask\n");
+ pr_err("unable to alloc powernow_k8_data cpumask\n");
ret_val = -ENOMEM;
goto err_out_mem;
}
@@ -885,9 +856,8 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data,
}
if (freq != (data->acpi_data.states[i].core_frequency * 1000)) {
- printk(KERN_INFO PFX "invalid freq entries "
- "%u kHz vs. %u kHz\n", freq,
- (unsigned int)
+ pr_info("invalid freq entries %u kHz vs. %u kHz\n",
+ freq, (unsigned int)
(data->acpi_data.states[i].core_frequency
* 1000));
invalidate_entry(powernow_table, i);
@@ -916,7 +886,7 @@ static int get_transition_latency(struct powernow_k8_data *data)
max_latency = cur_latency;
}
if (max_latency == 0) {
- pr_err(FW_WARN PFX "Invalid zero transition latency\n");
+ pr_err(FW_WARN "Invalid zero transition latency\n");
max_latency = 1;
}
/* value in usecs, needs to be in nanoseconds */
@@ -991,7 +961,7 @@ static long powernowk8_target_fn(void *arg)
checkvid = data->currvid;
if (pending_bit_stuck()) {
- printk(KERN_ERR PFX "failing targ, change pending bit set\n");
+ pr_err("failing targ, change pending bit set\n");
return -EIO;
}
@@ -1003,12 +973,11 @@ static long powernowk8_target_fn(void *arg)
return -EIO;
pr_debug("targ: curr fid 0x%x, vid 0x%x\n",
- data->currfid, data->currvid);
+ data->currfid, data->currvid);
if ((checkvid != data->currvid) ||
(checkfid != data->currfid)) {
- pr_info(PFX
- "error - out of sync, fix 0x%x 0x%x, vid 0x%x 0x%x\n",
+ pr_info("error - out of sync, fix 0x%x 0x%x, vid 0x%x 0x%x\n",
checkfid, data->currfid,
checkvid, data->currvid);
}
@@ -1020,7 +989,7 @@ static long powernowk8_target_fn(void *arg)
ret = transition_frequency_fidvid(data, newstate);
if (ret) {
- printk(KERN_ERR PFX "transition frequency failed\n");
+ pr_err("transition frequency failed\n");
mutex_unlock(&fidvid_mutex);
return 1;
}
@@ -1049,7 +1018,7 @@ static void powernowk8_cpu_init_on_cpu(void *_init_on_cpu)
struct init_on_cpu *init_on_cpu = _init_on_cpu;
if (pending_bit_stuck()) {
- printk(KERN_ERR PFX "failing init, change pending bit set\n");
+ pr_err("failing init, change pending bit set\n");
init_on_cpu->rc = -ENODEV;
return;
}
@@ -1064,11 +1033,10 @@ static void powernowk8_cpu_init_on_cpu(void *_init_on_cpu)
init_on_cpu->rc = 0;
}
-static const char missing_pss_msg[] =
- KERN_ERR
- FW_BUG PFX "No compatible ACPI _PSS objects found.\n"
- FW_BUG PFX "First, make sure Cool'N'Quiet is enabled in the BIOS.\n"
- FW_BUG PFX "If that doesn't help, try upgrading your BIOS.\n";
+#define MISSING_PSS_MSG \
+ FW_BUG "No compatible ACPI _PSS objects found.\n" \
+ FW_BUG "First, make sure Cool'N'Quiet is enabled in the BIOS.\n" \
+ FW_BUG "If that doesn't help, try upgrading your BIOS.\n"
/* per CPU init entry point to the driver */
static int powernowk8_cpu_init(struct cpufreq_policy *pol)
@@ -1083,7 +1051,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
- printk(KERN_ERR PFX "unable to alloc powernow_k8_data");
+ pr_err("unable to alloc powernow_k8_data");
return -ENOMEM;
}
@@ -1095,13 +1063,11 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
* an UP version, and is deprecated by AMD.
*/
if (num_online_cpus() != 1) {
- printk_once(missing_pss_msg);
+ pr_err_once(MISSING_PSS_MSG);
goto err_out;
}
if (pol->cpu != 0) {
- printk(KERN_ERR FW_BUG PFX "No ACPI _PSS objects for "
- "CPU other than CPU0. Complain to your BIOS "
- "vendor.\n");
+ pr_err(FW_BUG "No ACPI _PSS objects for CPU other than CPU0. Complain to your BIOS vendor.\n");
goto err_out;
}
rc = find_psb_table(data);
@@ -1129,7 +1095,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
/* min/max the cpu is capable of */
if (cpufreq_table_validate_and_show(pol, data->powernow_table)) {
- printk(KERN_ERR FW_BUG PFX "invalid powernow_table\n");
+ pr_err(FW_BUG "invalid powernow_table\n");
powernow_k8_cpu_exit_acpi(data);
kfree(data->powernow_table);
kfree(data);
@@ -1137,7 +1103,7 @@ static int powernowk8_cpu_init(struct cpufreq_policy *pol)
}
pr_debug("cpu_init done, current fid 0x%x, vid 0x%x\n",
- data->currfid, data->currvid);
+ data->currfid, data->currvid);
/* Point all the CPUs in this policy to the same data */
for_each_cpu(cpu, pol->cpus)
@@ -1220,12 +1186,12 @@ static void __request_acpi_cpufreq(void)
goto request;
if (strncmp(cur_drv, drv, min_t(size_t, strlen(cur_drv), strlen(drv))))
- pr_warn(PFX "WTF driver: %s\n", cur_drv);
+ pr_warn("WTF driver: %s\n", cur_drv);
return;
request:
- pr_warn(PFX "This CPU is not supported anymore, using acpi-cpufreq instead.\n");
+ pr_warn("This CPU is not supported anymore, using acpi-cpufreq instead.\n");
request_module(drv);
}
@@ -1260,7 +1226,7 @@ static int powernowk8_init(void)
if (ret)
return ret;
- pr_info(PFX "Found %d %s (%d cpu cores) (" VERSION ")\n",
+ pr_info("Found %d %s (%d cpu cores) (" VERSION ")\n",
num_online_nodes(), boot_cpu_data.x86_model_id, supported_cpus);
return ret;
@@ -1274,8 +1240,8 @@ static void __exit powernowk8_exit(void)
cpufreq_unregister_driver(&cpufreq_amd64_driver);
}
-MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com> and "
- "Mark Langsdorf <mark.langsdorf@amd.com>");
+MODULE_AUTHOR("Paul Devriendt <paul.devriendt@amd.com>");
+MODULE_AUTHOR("Mark Langsdorf <mark.langsdorf@amd.com>");
MODULE_DESCRIPTION("AMD Athlon 64 and Opteron processor frequency driver.");
MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/powernow-k8.h b/drivers/cpufreq/powernow-k8.h
index 79329d4d5abe..45ce11e86626 100644
--- a/drivers/cpufreq/powernow-k8.h
+++ b/drivers/cpufreq/powernow-k8.h
@@ -19,7 +19,7 @@ struct powernow_k8_data {
u32 vidmvs; /* usable value calculated from mvs */
u32 vstable; /* voltage stabilization time, units 20 us */
u32 plllock; /* pll lock time, units 1 us */
- u32 exttype; /* extended interface = 1 */
+ u32 exttype; /* extended interface = 1 */
/* keep track of the current fid / vid or pstate */
u32 currvid;
diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c
index af4968813e76..bb1d08dc8cc8 100644
--- a/drivers/cpufreq/powernv-cpufreq.c
+++ b/drivers/cpufreq/powernv-cpufreq.c
@@ -235,7 +235,7 @@ static void powernv_read_cpu_freq(void *arg)
* firmware for CPU 'cpu'. This value is reported through the sysfs
* file cpuinfo_cur_freq.
*/
-unsigned int powernv_cpufreq_get(unsigned int cpu)
+static unsigned int powernv_cpufreq_get(unsigned int cpu)
{
struct powernv_smp_call_data freq_data;
diff --git a/drivers/cpufreq/ppc_cbe_cpufreq.c b/drivers/cpufreq/ppc_cbe_cpufreq.c
index 5be8a48dba74..5a4c5a639f61 100644
--- a/drivers/cpufreq/ppc_cbe_cpufreq.c
+++ b/drivers/cpufreq/ppc_cbe_cpufreq.c
@@ -67,9 +67,10 @@ static int set_pmode(unsigned int cpu, unsigned int slow_mode)
static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
{
+ struct cpufreq_frequency_table *pos;
const u32 *max_freqp;
u32 max_freq;
- int i, cur_pmode;
+ int cur_pmode;
struct device_node *cpu;
cpu = of_get_cpu_node(policy->cpu, NULL);
@@ -102,9 +103,9 @@ static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
pr_debug("initializing frequency table\n");
/* initialize frequency table */
- for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) {
- cbe_freqs[i].frequency = max_freq / cbe_freqs[i].driver_data;
- pr_debug("%d: %d\n", i, cbe_freqs[i].frequency);
+ cpufreq_for_each_entry(pos, cbe_freqs) {
+ pos->frequency = max_freq / pos->driver_data;
+ pr_debug("%d: %d\n", (int)(pos - cbe_freqs), pos->frequency);
}
/* if DEBUG is enabled set_pmode() measures the latency
diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c
index 4626f90559b5..2fd53eaaec20 100644
--- a/drivers/cpufreq/s3c2416-cpufreq.c
+++ b/drivers/cpufreq/s3c2416-cpufreq.c
@@ -266,7 +266,7 @@ out:
static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
{
int count, v, i, found;
- struct cpufreq_frequency_table *freq;
+ struct cpufreq_frequency_table *pos;
struct s3c2416_dvfs *dvfs;
count = regulator_count_voltages(s3c_freq->vddarm);
@@ -275,12 +275,11 @@ static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
return;
}
- freq = s3c_freq->freq_table;
- while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) {
- if (freq->frequency == CPUFREQ_ENTRY_INVALID)
- continue;
+ if (!count)
+ goto out;
- dvfs = &s3c2416_dvfs_table[freq->driver_data];
+ cpufreq_for_each_valid_entry(pos, s3c_freq->freq_table) {
+ dvfs = &s3c2416_dvfs_table[pos->driver_data];
found = 0;
/* Check only the min-voltage, more is always ok on S3C2416 */
@@ -292,13 +291,12 @@ static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
if (!found) {
pr_debug("cpufreq: %dkHz unsupported by regulator\n",
- freq->frequency);
- freq->frequency = CPUFREQ_ENTRY_INVALID;
+ pos->frequency);
+ pos->frequency = CPUFREQ_ENTRY_INVALID;
}
-
- freq++;
}
+out:
/* Guessed */
s3c_freq->regulator_latency = 1 * 1000 * 1000;
}
@@ -338,7 +336,7 @@ static struct notifier_block s3c2416_cpufreq_reboot_notifier = {
static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
{
struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
- struct cpufreq_frequency_table *freq;
+ struct cpufreq_frequency_table *pos;
struct clk *msysclk;
unsigned long rate;
int ret;
@@ -427,31 +425,27 @@ static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
s3c_freq->regulator_latency = 0;
#endif
- freq = s3c_freq->freq_table;
- while (freq->frequency != CPUFREQ_TABLE_END) {
+ cpufreq_for_each_entry(pos, s3c_freq->freq_table) {
/* special handling for dvs mode */
- if (freq->driver_data == 0) {
+ if (pos->driver_data == 0) {
if (!s3c_freq->hclk) {
pr_debug("cpufreq: %dkHz unsupported as it would need unavailable dvs mode\n",
- freq->frequency);
- freq->frequency = CPUFREQ_ENTRY_INVALID;
+ pos->frequency);
+ pos->frequency = CPUFREQ_ENTRY_INVALID;
} else {
- freq++;
continue;
}
}
/* Check for frequencies we can generate */
rate = clk_round_rate(s3c_freq->armdiv,
- freq->frequency * 1000);
+ pos->frequency * 1000);
rate /= 1000;
- if (rate != freq->frequency) {
+ if (rate != pos->frequency) {
pr_debug("cpufreq: %dkHz unsupported by clock (clk_round_rate return %lu)\n",
- freq->frequency, rate);
- freq->frequency = CPUFREQ_ENTRY_INVALID;
+ pos->frequency, rate);
+ pos->frequency = CPUFREQ_ENTRY_INVALID;
}
-
- freq++;
}
/* Datasheet says PLL stabalisation time must be at least 300us,
diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c
index ff7d3ecb85f0..176e84cc3991 100644
--- a/drivers/cpufreq/s3c64xx-cpufreq.c
+++ b/drivers/cpufreq/s3c64xx-cpufreq.c
@@ -118,11 +118,10 @@ static void __init s3c64xx_cpufreq_config_regulator(void)
pr_err("Unable to check supported voltages\n");
}
- freq = s3c64xx_freq_table;
- while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) {
- if (freq->frequency == CPUFREQ_ENTRY_INVALID)
- continue;
+ if (!count)
+ goto out;
+ cpufreq_for_each_valid_entry(freq, s3c64xx_freq_table) {
dvfs = &s3c64xx_dvfs_table[freq->driver_data];
found = 0;
@@ -137,10 +136,9 @@ static void __init s3c64xx_cpufreq_config_regulator(void)
freq->frequency);
freq->frequency = CPUFREQ_ENTRY_INVALID;
}
-
- freq++;
}
+out:
/* Guess based on having to do an I2C/SPI write; in future we
* will be able to query the regulator performance here. */
regulator_latency = 1 * 1000 * 1000;
@@ -179,8 +177,7 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
}
#endif
- freq = s3c64xx_freq_table;
- while (freq->frequency != CPUFREQ_TABLE_END) {
+ cpufreq_for_each_entry(freq, s3c64xx_freq_table) {
unsigned long r;
/* Check for frequencies we can generate */
@@ -196,8 +193,6 @@ static int s3c64xx_cpufreq_driver_init(struct cpufreq_policy *policy)
* frequency is the maximum we can support. */
if (!vddarm && freq->frequency > clk_get_rate(policy->clk) / 1000)
freq->frequency = CPUFREQ_ENTRY_INVALID;
-
- freq++;
}
/* Datasheet says PLL stabalisation time (if we were to use
diff --git a/drivers/cpufreq/s5pv210-cpufreq.c b/drivers/cpufreq/s5pv210-cpufreq.c
index ab2c1a40d437..19a10b89fef7 100644
--- a/drivers/cpufreq/s5pv210-cpufreq.c
+++ b/drivers/cpufreq/s5pv210-cpufreq.c
@@ -175,10 +175,8 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
mutex_lock(&set_freq_lock);
if (no_cpufreq_access) {
-#ifdef CONFIG_PM_VERBOSE
- pr_err("%s:%d denied access to %s as it is disabled"
- "temporarily\n", __FILE__, __LINE__, __func__);
-#endif
+ pr_err("Denied access to %s as it is disabled temporarily\n",
+ __func__);
ret = -EINVAL;
goto exit;
}
diff --git a/drivers/cpufreq/speedstep-centrino.c b/drivers/cpufreq/speedstep-centrino.c
index 6723f0390f20..7d4a31571608 100644
--- a/drivers/cpufreq/speedstep-centrino.c
+++ b/drivers/cpufreq/speedstep-centrino.c
@@ -28,7 +28,7 @@
#include <asm/cpu_device_id.h>
#define PFX "speedstep-centrino: "
-#define MAINTAINER "cpufreq@vger.kernel.org"
+#define MAINTAINER "linux-pm@vger.kernel.org"
#define INTEL_MSR_RANGE (0xffff)
diff --git a/drivers/cpufreq/tegra-cpufreq.c b/drivers/cpufreq/tegra-cpufreq.c
index 63f00598a251..6e774c6ac20b 100644
--- a/drivers/cpufreq/tegra-cpufreq.c
+++ b/drivers/cpufreq/tegra-cpufreq.c
@@ -82,9 +82,9 @@ out:
return ret;
}
-static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
- unsigned long rate)
+static int tegra_target(struct cpufreq_policy *policy, unsigned int index)
{
+ unsigned long rate = freq_table[index].frequency;
int ret = 0;
/*
@@ -106,11 +106,6 @@ static int tegra_update_cpu_speed(struct cpufreq_policy *policy,
return ret;
}
-static int tegra_target(struct cpufreq_policy *policy, unsigned int index)
-{
- return tegra_update_cpu_speed(policy, freq_table[index].frequency);
-}
-
static int tegra_cpu_init(struct cpufreq_policy *policy)
{
int ret;
diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm
index ae1d78ea7df7..b6d69e899f5d 100644
--- a/drivers/cpuidle/Kconfig.arm
+++ b/drivers/cpuidle/Kconfig.arm
@@ -18,6 +18,12 @@ config ARM_BIG_LITTLE_CPUIDLE
define different C-states for little and big cores through the
multiple CPU idle drivers infrastructure.
+config ARM_CLPS711X_CPUIDLE
+ bool "CPU Idle Driver for CLPS711X processors"
+ depends on ARCH_CLPS711X || COMPILE_TEST
+ help
+ Select this to enable cpuidle on Cirrus Logic CLPS711X SOCs.
+
config ARM_HIGHBANK_CPUIDLE
bool "CPU Idle Driver for Calxeda processors"
depends on ARM_PSCI
diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile
index cd3ab59f8461..9b5b2b560d70 100644
--- a/drivers/cpuidle/Makefile
+++ b/drivers/cpuidle/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED) += coupled.o
# ARM SoC drivers
obj-$(CONFIG_ARM_ARMADA_370_XP_CPUIDLE) += cpuidle-armada-370-xp.o
obj-$(CONFIG_ARM_BIG_LITTLE_CPUIDLE) += cpuidle-big_little.o
+obj-$(CONFIG_ARM_CLPS711X_CPUIDLE) += cpuidle-clps711x.o
obj-$(CONFIG_ARM_HIGHBANK_CPUIDLE) += cpuidle-calxeda.o
obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE) += cpuidle-kirkwood.o
obj-$(CONFIG_ARM_ZYNQ_CPUIDLE) += cpuidle-zynq.o
diff --git a/drivers/cpuidle/cpuidle-clps711x.c b/drivers/cpuidle/cpuidle-clps711x.c
new file mode 100644
index 000000000000..5243811daa6e
--- /dev/null
+++ b/drivers/cpuidle/cpuidle-clps711x.c
@@ -0,0 +1,64 @@
+/*
+ * CLPS711X CPU idle driver
+ *
+ * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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/cpuidle.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define CLPS711X_CPUIDLE_NAME "clps711x-cpuidle"
+
+static void __iomem *clps711x_halt;
+
+static int clps711x_cpuidle_halt(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ writel(0xaa, clps711x_halt);
+
+ return index;
+}
+
+static struct cpuidle_driver clps711x_idle_driver = {
+ .name = CLPS711X_CPUIDLE_NAME,
+ .owner = THIS_MODULE,
+ .states[0] = {
+ .name = "HALT",
+ .desc = "CLPS711X HALT",
+ .enter = clps711x_cpuidle_halt,
+ .exit_latency = 1,
+ },
+ .state_count = 1,
+};
+
+static int __init clps711x_cpuidle_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ clps711x_halt = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(clps711x_halt))
+ return PTR_ERR(clps711x_halt);
+
+ return cpuidle_register(&clps711x_idle_driver, NULL);
+}
+
+static struct platform_driver clps711x_cpuidle_driver = {
+ .driver = {
+ .name = CLPS711X_CPUIDLE_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+module_platform_driver_probe(clps711x_cpuidle_driver, clps711x_cpuidle_probe);
+
+MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
+MODULE_DESCRIPTION("CLPS711X CPU idle driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index 7d2f43550700..49e74c1fc639 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -70,19 +70,20 @@ config ARM_EXYNOS4_BUS_DEVFREQ
depends on (CPU_EXYNOS4210 || SOC_EXYNOS4212 || SOC_EXYNOS4412) && !ARCH_MULTIPLATFORM
select ARCH_HAS_OPP
select DEVFREQ_GOV_SIMPLE_ONDEMAND
+ select PM_OPP
help
This adds the DEVFREQ driver for Exynos4210 memory bus (vdd_int)
and Exynos4212/4412 memory interface and bus (vdd_mif + vdd_int).
It reads PPMU counters of memory controllers and adjusts
the operating frequencies and voltages with OPP support.
- To operate with optimal voltages, ASV support is required
- (CONFIG_EXYNOS_ASV).
+ This does not yet operate with optimal voltages.
config ARM_EXYNOS5_BUS_DEVFREQ
bool "ARM Exynos5250 Bus DEVFREQ Driver"
depends on SOC_EXYNOS5250
select ARCH_HAS_OPP
select DEVFREQ_GOV_SIMPLE_ONDEMAND
+ select PM_OPP
help
This adds the DEVFREQ driver for Exynos5250 bus interface (vdd_int).
It reads PPMU counters of memory controllers and adjusts the
diff --git a/drivers/devfreq/devfreq.c b/drivers/devfreq/devfreq.c
index 2042ec3656ba..9f90369dd6bd 100644
--- a/drivers/devfreq/devfreq.c
+++ b/drivers/devfreq/devfreq.c
@@ -394,7 +394,7 @@ static int devfreq_notifier_call(struct notifier_block *nb, unsigned long type,
* @devfreq: the devfreq struct
* @skip: skip calling device_unregister().
*/
-static void _remove_devfreq(struct devfreq *devfreq, bool skip)
+static void _remove_devfreq(struct devfreq *devfreq)
{
mutex_lock(&devfreq_list_lock);
if (IS_ERR(find_device_devfreq(devfreq->dev.parent))) {
@@ -412,11 +412,6 @@ static void _remove_devfreq(struct devfreq *devfreq, bool skip)
if (devfreq->profile->exit)
devfreq->profile->exit(devfreq->dev.parent);
- if (!skip && get_device(&devfreq->dev)) {
- device_unregister(&devfreq->dev);
- put_device(&devfreq->dev);
- }
-
mutex_destroy(&devfreq->lock);
kfree(devfreq);
}
@@ -426,14 +421,12 @@ static void _remove_devfreq(struct devfreq *devfreq, bool skip)
* @dev: the devfreq device
*
* This calls _remove_devfreq() if _remove_devfreq() is not called.
- * Note that devfreq_dev_release() could be called by _remove_devfreq() as
- * well as by others unregistering the device.
*/
static void devfreq_dev_release(struct device *dev)
{
struct devfreq *devfreq = to_devfreq(dev);
- _remove_devfreq(devfreq, true);
+ _remove_devfreq(devfreq);
}
/**
@@ -544,12 +537,76 @@ int devfreq_remove_device(struct devfreq *devfreq)
if (!devfreq)
return -EINVAL;
- _remove_devfreq(devfreq, false);
+ device_unregister(&devfreq->dev);
+ put_device(&devfreq->dev);
return 0;
}
EXPORT_SYMBOL(devfreq_remove_device);
+static int devm_devfreq_dev_match(struct device *dev, void *res, void *data)
+{
+ struct devfreq **r = res;
+
+ if (WARN_ON(!r || !*r))
+ return 0;
+
+ return *r == data;
+}
+
+static void devm_devfreq_dev_release(struct device *dev, void *res)
+{
+ devfreq_remove_device(*(struct devfreq **)res);
+}
+
+/**
+ * devm_devfreq_add_device() - Resource-managed devfreq_add_device()
+ * @dev: the device to add devfreq feature.
+ * @profile: device-specific profile to run devfreq.
+ * @governor_name: name of the policy to choose frequency.
+ * @data: private data for the governor. The devfreq framework does not
+ * touch this value.
+ *
+ * This function manages automatically the memory of devfreq device using device
+ * resource management and simplify the free operation for memory of devfreq
+ * device.
+ */
+struct devfreq *devm_devfreq_add_device(struct device *dev,
+ struct devfreq_dev_profile *profile,
+ const char *governor_name,
+ void *data)
+{
+ struct devfreq **ptr, *devfreq;
+
+ ptr = devres_alloc(devm_devfreq_dev_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ devfreq = devfreq_add_device(dev, profile, governor_name, data);
+ if (IS_ERR(devfreq)) {
+ devres_free(ptr);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ *ptr = devfreq;
+ devres_add(dev, ptr);
+
+ return devfreq;
+}
+EXPORT_SYMBOL(devm_devfreq_add_device);
+
+/**
+ * devm_devfreq_remove_device() - Resource-managed devfreq_remove_device()
+ * @dev: the device to add devfreq feature.
+ * @devfreq: the devfreq instance to be removed
+ */
+void devm_devfreq_remove_device(struct device *dev, struct devfreq *devfreq)
+{
+ WARN_ON(devres_release(dev, devm_devfreq_dev_release,
+ devm_devfreq_dev_match, devfreq));
+}
+EXPORT_SYMBOL(devm_devfreq_remove_device);
+
/**
* devfreq_suspend_device() - Suspend devfreq of a device.
* @devfreq: the devfreq instance to be suspended
@@ -1112,6 +1169,54 @@ int devfreq_unregister_opp_notifier(struct device *dev, struct devfreq *devfreq)
return ret;
}
+static void devm_devfreq_opp_release(struct device *dev, void *res)
+{
+ devfreq_unregister_opp_notifier(dev, *(struct devfreq **)res);
+}
+
+/**
+ * devm_ devfreq_register_opp_notifier()
+ * - Resource-managed devfreq_register_opp_notifier()
+ * @dev: The devfreq user device. (parent of devfreq)
+ * @devfreq: The devfreq object.
+ */
+int devm_devfreq_register_opp_notifier(struct device *dev,
+ struct devfreq *devfreq)
+{
+ struct devfreq **ptr;
+ int ret;
+
+ ptr = devres_alloc(devm_devfreq_opp_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return -ENOMEM;
+
+ ret = devfreq_register_opp_notifier(dev, devfreq);
+ if (ret) {
+ devres_free(ptr);
+ return ret;
+ }
+
+ *ptr = devfreq;
+ devres_add(dev, ptr);
+
+ return 0;
+}
+EXPORT_SYMBOL(devm_devfreq_register_opp_notifier);
+
+/**
+ * devm_devfreq_unregister_opp_notifier()
+ * - Resource-managed devfreq_unregister_opp_notifier()
+ * @dev: The devfreq user device. (parent of devfreq)
+ * @devfreq: The devfreq object.
+ */
+void devm_devfreq_unregister_opp_notifier(struct device *dev,
+ struct devfreq *devfreq)
+{
+ WARN_ON(devres_release(dev, devm_devfreq_opp_release,
+ devm_devfreq_dev_match, devfreq));
+}
+EXPORT_SYMBOL(devm_devfreq_unregister_opp_notifier);
+
MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
MODULE_DESCRIPTION("devfreq class support");
MODULE_LICENSE("GPL");
diff --git a/drivers/devfreq/exynos/Makefile b/drivers/devfreq/exynos/Makefile
index bfaaf5b0d61d..49bc9175f923 100644
--- a/drivers/devfreq/exynos/Makefile
+++ b/drivers/devfreq/exynos/Makefile
@@ -1,3 +1,3 @@
# Exynos DEVFREQ Drivers
-obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos4_bus.o
+obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos_ppmu.o exynos4_bus.o
obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos_ppmu.o exynos5_bus.o
diff --git a/drivers/devfreq/exynos/exynos4_bus.c b/drivers/devfreq/exynos/exynos4_bus.c
index e07b0c68c715..d9b08d3b6830 100644
--- a/drivers/devfreq/exynos/exynos4_bus.c
+++ b/drivers/devfreq/exynos/exynos4_bus.c
@@ -25,13 +25,9 @@
#include <linux/regulator/consumer.h>
#include <linux/module.h>
-/* Exynos4 ASV has been in the mailing list, but not upstreamed, yet. */
-#ifdef CONFIG_EXYNOS_ASV
-extern unsigned int exynos_result_of_asv;
-#endif
-
#include <mach/map.h>
+#include "exynos_ppmu.h"
#include "exynos4_bus.h"
#define MAX_SAFEVOLT 1200000 /* 1.2V */
@@ -44,22 +40,6 @@ enum exynos4_busf_type {
/* Assume that the bus is saturated if the utilization is 40% */
#define BUS_SATURATION_RATIO 40
-enum ppmu_counter {
- PPMU_PMNCNT0 = 0,
- PPMU_PMCCNT1,
- PPMU_PMNCNT2,
- PPMU_PMNCNT3,
- PPMU_PMNCNT_MAX,
-};
-struct exynos4_ppmu {
- void __iomem *hw_base;
- unsigned int ccnt;
- unsigned int event;
- unsigned int count[PPMU_PMNCNT_MAX];
- bool ccnt_overflow;
- bool count_overflow[PPMU_PMNCNT_MAX];
-};
-
enum busclk_level_idx {
LV_0 = 0,
LV_1,
@@ -68,6 +48,13 @@ enum busclk_level_idx {
LV_4,
_LV_END
};
+
+enum exynos_ppmu_idx {
+ PPMU_DMC0,
+ PPMU_DMC1,
+ PPMU_END,
+};
+
#define EX4210_LV_MAX LV_2
#define EX4x12_LV_MAX LV_4
#define EX4210_LV_NUM (LV_2 + 1)
@@ -91,7 +78,7 @@ struct busfreq_data {
struct regulator *vdd_int;
struct regulator *vdd_mif; /* Exynos4412/4212 only */
struct busfreq_opp_info curr_oppinfo;
- struct exynos4_ppmu dmc[2];
+ struct busfreq_ppmu_data ppmu_data;
struct notifier_block pm_notifier;
struct mutex lock;
@@ -101,12 +88,6 @@ struct busfreq_data {
unsigned int top_divtable[_LV_END];
};
-struct bus_opp_table {
- unsigned int idx;
- unsigned long clk;
- unsigned long volt;
-};
-
/* 4210 controls clock of mif and voltage of int */
static struct bus_opp_table exynos4210_busclk_table[] = {
{LV_0, 400000, 1150000},
@@ -524,57 +505,6 @@ static int exynos4x12_set_busclk(struct busfreq_data *data,
return 0;
}
-
-static void busfreq_mon_reset(struct busfreq_data *data)
-{
- unsigned int i;
-
- for (i = 0; i < 2; i++) {
- void __iomem *ppmu_base = data->dmc[i].hw_base;
-
- /* Reset PPMU */
- __raw_writel(0x8000000f, ppmu_base + 0xf010);
- __raw_writel(0x8000000f, ppmu_base + 0xf050);
- __raw_writel(0x6, ppmu_base + 0xf000);
- __raw_writel(0x0, ppmu_base + 0xf100);
-
- /* Set PPMU Event */
- data->dmc[i].event = 0x6;
- __raw_writel(((data->dmc[i].event << 12) | 0x1),
- ppmu_base + 0xfc);
-
- /* Start PPMU */
- __raw_writel(0x1, ppmu_base + 0xf000);
- }
-}
-
-static void exynos4_read_ppmu(struct busfreq_data *data)
-{
- int i, j;
-
- for (i = 0; i < 2; i++) {
- void __iomem *ppmu_base = data->dmc[i].hw_base;
- u32 overflow;
-
- /* Stop PPMU */
- __raw_writel(0x0, ppmu_base + 0xf000);
-
- /* Update local data from PPMU */
- overflow = __raw_readl(ppmu_base + 0xf050);
-
- data->dmc[i].ccnt = __raw_readl(ppmu_base + 0xf100);
- data->dmc[i].ccnt_overflow = overflow & (1 << 31);
-
- for (j = 0; j < PPMU_PMNCNT_MAX; j++) {
- data->dmc[i].count[j] = __raw_readl(
- ppmu_base + (0xf110 + (0x10 * j)));
- data->dmc[i].count_overflow[j] = overflow & (1 << j);
- }
- }
-
- busfreq_mon_reset(data);
-}
-
static int exynos4x12_get_intspec(unsigned long mifclk)
{
int i = 0;
@@ -698,84 +628,35 @@ out:
return err;
}
-static int exynos4_get_busier_dmc(struct busfreq_data *data)
-{
- u64 p0 = data->dmc[0].count[0];
- u64 p1 = data->dmc[1].count[0];
-
- p0 *= data->dmc[1].ccnt;
- p1 *= data->dmc[0].ccnt;
-
- if (data->dmc[1].ccnt == 0)
- return 0;
-
- if (p0 > p1)
- return 0;
- return 1;
-}
-
static int exynos4_bus_get_dev_status(struct device *dev,
struct devfreq_dev_status *stat)
{
struct busfreq_data *data = dev_get_drvdata(dev);
- int busier_dmc;
- int cycles_x2 = 2; /* 2 x cycles */
- void __iomem *addr;
- u32 timing;
- u32 memctrl;
-
- exynos4_read_ppmu(data);
- busier_dmc = exynos4_get_busier_dmc(data);
- stat->current_frequency = data->curr_oppinfo.rate;
+ struct busfreq_ppmu_data *ppmu_data = &data->ppmu_data;
+ int busier;
- if (busier_dmc)
- addr = S5P_VA_DMC1;
- else
- addr = S5P_VA_DMC0;
-
- memctrl = __raw_readl(addr + 0x04); /* one of DDR2/3/LPDDR2 */
- timing = __raw_readl(addr + 0x38); /* CL or WL/RL values */
-
- switch ((memctrl >> 8) & 0xf) {
- case 0x4: /* DDR2 */
- cycles_x2 = ((timing >> 16) & 0xf) * 2;
- break;
- case 0x5: /* LPDDR2 */
- case 0x6: /* DDR3 */
- cycles_x2 = ((timing >> 8) & 0xf) + ((timing >> 0) & 0xf);
- break;
- default:
- pr_err("%s: Unknown Memory Type(%d).\n", __func__,
- (memctrl >> 8) & 0xf);
- return -EINVAL;
- }
+ exynos_read_ppmu(ppmu_data);
+ busier = exynos_get_busier_ppmu(ppmu_data);
+ stat->current_frequency = data->curr_oppinfo.rate;
/* Number of cycles spent on memory access */
- stat->busy_time = data->dmc[busier_dmc].count[0] / 2 * (cycles_x2 + 2);
+ stat->busy_time = ppmu_data->ppmu[busier].count[PPMU_PMNCNT3];
stat->busy_time *= 100 / BUS_SATURATION_RATIO;
- stat->total_time = data->dmc[busier_dmc].ccnt;
+ stat->total_time = ppmu_data->ppmu[busier].ccnt;
/* If the counters have overflown, retry */
- if (data->dmc[busier_dmc].ccnt_overflow ||
- data->dmc[busier_dmc].count_overflow[0])
+ if (ppmu_data->ppmu[busier].ccnt_overflow ||
+ ppmu_data->ppmu[busier].count_overflow[0])
return -EAGAIN;
return 0;
}
-static void exynos4_bus_exit(struct device *dev)
-{
- struct busfreq_data *data = dev_get_drvdata(dev);
-
- devfreq_unregister_opp_notifier(dev, data->devfreq);
-}
-
static struct devfreq_dev_profile exynos4_devfreq_profile = {
.initial_freq = 400000,
.polling_ms = 50,
.target = exynos4_bus_target,
.get_dev_status = exynos4_bus_get_dev_status,
- .exit = exynos4_bus_exit,
};
static int exynos4210_init_tables(struct busfreq_data *data)
@@ -837,11 +718,11 @@ static int exynos4210_init_tables(struct busfreq_data *data)
data->top_divtable[i] = tmp;
}
-#ifdef CONFIG_EXYNOS_ASV
- tmp = exynos4_result_of_asv;
-#else
+ /*
+ * TODO: init tmp based on busfreq_data
+ * (device-tree or platform-data)
+ */
tmp = 0; /* Max voltages for the reliability of the unknown */
-#endif
pr_debug("ASV Group of Exynos4 is %d\n", tmp);
/* Use merged grouping for voltage */
@@ -922,11 +803,7 @@ static int exynos4x12_init_tables(struct busfreq_data *data)
data->dmc_divtable[i] = tmp;
}
-#ifdef CONFIG_EXYNOS_ASV
- tmp = exynos4_result_of_asv;
-#else
tmp = 0; /* Max voltages for the reliability of the unknown */
-#endif
if (tmp > 8)
tmp = 0;
@@ -1020,6 +897,7 @@ unlock:
static int exynos4_busfreq_probe(struct platform_device *pdev)
{
struct busfreq_data *data;
+ struct busfreq_ppmu_data *ppmu_data;
struct dev_pm_opp *opp;
struct device *dev = &pdev->dev;
int err = 0;
@@ -1030,9 +908,19 @@ static int exynos4_busfreq_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ ppmu_data = &data->ppmu_data;
+ ppmu_data->ppmu_end = PPMU_END;
+ ppmu_data->ppmu = devm_kzalloc(dev,
+ sizeof(struct exynos_ppmu) * PPMU_END,
+ GFP_KERNEL);
+ if (!ppmu_data->ppmu) {
+ dev_err(dev, "Failed to allocate memory for exynos_ppmu\n");
+ return -ENOMEM;
+ }
+
data->type = pdev->id_entry->driver_data;
- data->dmc[0].hw_base = S5P_VA_DMC0;
- data->dmc[1].hw_base = S5P_VA_DMC1;
+ ppmu_data->ppmu[PPMU_DMC0].hw_base = S5P_VA_DMC0;
+ ppmu_data->ppmu[PPMU_DMC1].hw_base = S5P_VA_DMC1;
data->pm_notifier.notifier_call = exynos4_busfreq_pm_notifier_event;
data->dev = dev;
mutex_init(&data->lock);
@@ -1048,8 +936,11 @@ static int exynos4_busfreq_probe(struct platform_device *pdev)
dev_err(dev, "Cannot determine the device id %d\n", data->type);
err = -EINVAL;
}
- if (err)
+ if (err) {
+ dev_err(dev, "Cannot initialize busfreq table %d\n",
+ data->type);
return err;
+ }
data->vdd_int = devm_regulator_get(dev, "vdd_int");
if (IS_ERR(data->vdd_int)) {
@@ -1079,19 +970,28 @@ static int exynos4_busfreq_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
- busfreq_mon_reset(data);
-
- data->devfreq = devfreq_add_device(dev, &exynos4_devfreq_profile,
+ data->devfreq = devm_devfreq_add_device(dev, &exynos4_devfreq_profile,
"simple_ondemand", NULL);
if (IS_ERR(data->devfreq))
return PTR_ERR(data->devfreq);
- devfreq_register_opp_notifier(dev, data->devfreq);
+ /*
+ * Start PPMU (Performance Profiling Monitoring Unit) to check
+ * utilization of each IP in the Exynos4 SoC.
+ */
+ busfreq_mon_reset(ppmu_data);
+ /* Register opp_notifier for Exynos4 busfreq */
+ err = devm_devfreq_register_opp_notifier(dev, data->devfreq);
+ if (err < 0) {
+ dev_err(dev, "Failed to register opp notifier\n");
+ return err;
+ }
+
+ /* Register pm_notifier for Exynos4 busfreq */
err = register_pm_notifier(&data->pm_notifier);
if (err) {
dev_err(dev, "Failed to setup pm notifier\n");
- devfreq_remove_device(data->devfreq);
return err;
}
@@ -1102,23 +1002,24 @@ static int exynos4_busfreq_remove(struct platform_device *pdev)
{
struct busfreq_data *data = platform_get_drvdata(pdev);
+ /* Unregister all of notifier chain */
unregister_pm_notifier(&data->pm_notifier);
- devfreq_remove_device(data->devfreq);
return 0;
}
+#ifdef CONFIG_PM_SLEEP
static int exynos4_busfreq_resume(struct device *dev)
{
struct busfreq_data *data = dev_get_drvdata(dev);
+ struct busfreq_ppmu_data *ppmu_data = &data->ppmu_data;
- busfreq_mon_reset(data);
+ busfreq_mon_reset(ppmu_data);
return 0;
}
+#endif
-static const struct dev_pm_ops exynos4_busfreq_pm = {
- .resume = exynos4_busfreq_resume,
-};
+static SIMPLE_DEV_PM_OPS(exynos4_busfreq_pm_ops, NULL, exynos4_busfreq_resume);
static const struct platform_device_id exynos4_busfreq_id[] = {
{ "exynos4210-busfreq", TYPE_BUSF_EXYNOS4210 },
@@ -1134,7 +1035,7 @@ static struct platform_driver exynos4_busfreq_driver = {
.driver = {
.name = "exynos4-busfreq",
.owner = THIS_MODULE,
- .pm = &exynos4_busfreq_pm,
+ .pm = &exynos4_busfreq_pm_ops,
},
};
diff --git a/drivers/devfreq/exynos/exynos5_bus.c b/drivers/devfreq/exynos/exynos5_bus.c
index 6eef1f7397c6..6cd0392e2798 100644
--- a/drivers/devfreq/exynos/exynos5_bus.c
+++ b/drivers/devfreq/exynos/exynos5_bus.c
@@ -50,7 +50,7 @@ struct busfreq_data_int {
struct device *dev;
struct devfreq *devfreq;
struct regulator *vdd_int;
- struct exynos_ppmu ppmu[PPMU_END];
+ struct busfreq_ppmu_data ppmu_data;
unsigned long curr_freq;
bool disabled;
@@ -75,49 +75,6 @@ static struct int_bus_opp_table exynos5_int_opp_table[] = {
{0, 0, 0},
};
-static void busfreq_mon_reset(struct busfreq_data_int *data)
-{
- unsigned int i;
-
- for (i = PPMU_RIGHT; i < PPMU_END; i++) {
- void __iomem *ppmu_base = data->ppmu[i].hw_base;
-
- /* Reset the performance and cycle counters */
- exynos_ppmu_reset(ppmu_base);
-
- /* Setup count registers to monitor read/write transactions */
- data->ppmu[i].event[PPMU_PMNCNT3] = RDWR_DATA_COUNT;
- exynos_ppmu_setevent(ppmu_base, PPMU_PMNCNT3,
- data->ppmu[i].event[PPMU_PMNCNT3]);
-
- exynos_ppmu_start(ppmu_base);
- }
-}
-
-static void exynos5_read_ppmu(struct busfreq_data_int *data)
-{
- int i, j;
-
- for (i = PPMU_RIGHT; i < PPMU_END; i++) {
- void __iomem *ppmu_base = data->ppmu[i].hw_base;
-
- exynos_ppmu_stop(ppmu_base);
-
- /* Update local data from PPMU */
- data->ppmu[i].ccnt = __raw_readl(ppmu_base + PPMU_CCNT);
-
- for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
- if (data->ppmu[i].event[j] == 0)
- data->ppmu[i].count[j] = 0;
- else
- data->ppmu[i].count[j] =
- exynos_ppmu_read(ppmu_base, j);
- }
- }
-
- busfreq_mon_reset(data);
-}
-
static int exynos5_int_setvolt(struct busfreq_data_int *data,
unsigned long volt)
{
@@ -185,59 +142,33 @@ out:
return err;
}
-static int exynos5_get_busier_dmc(struct busfreq_data_int *data)
-{
- int i, j;
- int busy = 0;
- unsigned int temp = 0;
-
- for (i = PPMU_RIGHT; i < PPMU_END; i++) {
- for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
- if (data->ppmu[i].count[j] > temp) {
- temp = data->ppmu[i].count[j];
- busy = i;
- }
- }
- }
-
- return busy;
-}
-
static int exynos5_int_get_dev_status(struct device *dev,
struct devfreq_dev_status *stat)
{
struct platform_device *pdev = container_of(dev, struct platform_device,
dev);
struct busfreq_data_int *data = platform_get_drvdata(pdev);
+ struct busfreq_ppmu_data *ppmu_data = &data->ppmu_data;
int busier_dmc;
- exynos5_read_ppmu(data);
- busier_dmc = exynos5_get_busier_dmc(data);
+ exynos_read_ppmu(ppmu_data);
+ busier_dmc = exynos_get_busier_ppmu(ppmu_data);
stat->current_frequency = data->curr_freq;
/* Number of cycles spent on memory access */
- stat->busy_time = data->ppmu[busier_dmc].count[PPMU_PMNCNT3];
+ stat->busy_time = ppmu_data->ppmu[busier_dmc].count[PPMU_PMNCNT3];
stat->busy_time *= 100 / INT_BUS_SATURATION_RATIO;
- stat->total_time = data->ppmu[busier_dmc].ccnt;
+ stat->total_time = ppmu_data->ppmu[busier_dmc].ccnt;
return 0;
}
-static void exynos5_int_exit(struct device *dev)
-{
- struct platform_device *pdev = container_of(dev, struct platform_device,
- dev);
- struct busfreq_data_int *data = platform_get_drvdata(pdev);
-
- devfreq_unregister_opp_notifier(dev, data->devfreq);
-}
static struct devfreq_dev_profile exynos5_devfreq_int_profile = {
.initial_freq = 160000,
.polling_ms = 100,
.target = exynos5_busfreq_int_target,
.get_dev_status = exynos5_int_get_dev_status,
- .exit = exynos5_int_exit,
};
static int exynos5250_init_int_tables(struct busfreq_data_int *data)
@@ -315,6 +246,7 @@ unlock:
static int exynos5_busfreq_int_probe(struct platform_device *pdev)
{
struct busfreq_data_int *data;
+ struct busfreq_ppmu_data *ppmu_data;
struct dev_pm_opp *opp;
struct device *dev = &pdev->dev;
struct device_node *np;
@@ -330,16 +262,26 @@ static int exynos5_busfreq_int_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ ppmu_data = &data->ppmu_data;
+ ppmu_data->ppmu_end = PPMU_END;
+ ppmu_data->ppmu = devm_kzalloc(dev,
+ sizeof(struct exynos_ppmu) * PPMU_END,
+ GFP_KERNEL);
+ if (!ppmu_data->ppmu) {
+ dev_err(dev, "Failed to allocate memory for exynos_ppmu\n");
+ return -ENOMEM;
+ }
+
np = of_find_compatible_node(NULL, NULL, "samsung,exynos5250-ppmu");
if (np == NULL) {
pr_err("Unable to find PPMU node\n");
return -ENOENT;
}
- for (i = PPMU_RIGHT; i < PPMU_END; i++) {
+ for (i = 0; i < ppmu_data->ppmu_end; i++) {
/* map PPMU memory region */
- data->ppmu[i].hw_base = of_iomap(np, i);
- if (data->ppmu[i].hw_base == NULL) {
+ ppmu_data->ppmu[i].hw_base = of_iomap(np, i);
+ if (ppmu_data->ppmu[i].hw_base == NULL) {
dev_err(&pdev->dev, "failed to map memory region\n");
return -ENOMEM;
}
@@ -390,32 +332,29 @@ static int exynos5_busfreq_int_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
- busfreq_mon_reset(data);
+ busfreq_mon_reset(ppmu_data);
- data->devfreq = devfreq_add_device(dev, &exynos5_devfreq_int_profile,
+ data->devfreq = devm_devfreq_add_device(dev, &exynos5_devfreq_int_profile,
"simple_ondemand", NULL);
+ if (IS_ERR(data->devfreq))
+ return PTR_ERR(data->devfreq);
- if (IS_ERR(data->devfreq)) {
- err = PTR_ERR(data->devfreq);
- goto err_devfreq_add;
+ err = devm_devfreq_register_opp_notifier(dev, data->devfreq);
+ if (err < 0) {
+ dev_err(dev, "Failed to register opp notifier\n");
+ return err;
}
- devfreq_register_opp_notifier(dev, data->devfreq);
-
err = register_pm_notifier(&data->pm_notifier);
if (err) {
dev_err(dev, "Failed to setup pm notifier\n");
- goto err_devfreq_add;
+ return err;
}
/* TODO: Add a new QOS class for int/mif bus */
pm_qos_add_request(&data->int_req, PM_QOS_NETWORK_THROUGHPUT, -1);
return 0;
-
-err_devfreq_add:
- devfreq_remove_device(data->devfreq);
- return err;
}
static int exynos5_busfreq_int_remove(struct platform_device *pdev)
@@ -424,24 +363,27 @@ static int exynos5_busfreq_int_remove(struct platform_device *pdev)
pm_qos_remove_request(&data->int_req);
unregister_pm_notifier(&data->pm_notifier);
- devfreq_remove_device(data->devfreq);
return 0;
}
+#ifdef CONFIG_PM_SLEEP
static int exynos5_busfreq_int_resume(struct device *dev)
{
struct platform_device *pdev = container_of(dev, struct platform_device,
dev);
struct busfreq_data_int *data = platform_get_drvdata(pdev);
+ struct busfreq_ppmu_data *ppmu_data = &data->ppmu_data;
- busfreq_mon_reset(data);
+ busfreq_mon_reset(ppmu_data);
return 0;
}
-
static const struct dev_pm_ops exynos5_busfreq_int_pm = {
.resume = exynos5_busfreq_int_resume,
};
+#endif
+static SIMPLE_DEV_PM_OPS(exynos5_busfreq_int_pm_ops, NULL,
+ exynos5_busfreq_int_resume);
/* platform device pointer for exynos5 devfreq device. */
static struct platform_device *exynos5_devfreq_pdev;
@@ -452,7 +394,7 @@ static struct platform_driver exynos5_busfreq_int_driver = {
.driver = {
.name = "exynos5-bus-int",
.owner = THIS_MODULE,
- .pm = &exynos5_busfreq_int_pm,
+ .pm = &exynos5_busfreq_int_pm_ops,
},
};
diff --git a/drivers/devfreq/exynos/exynos_ppmu.c b/drivers/devfreq/exynos/exynos_ppmu.c
index 85fc5ac1036a..75fcc5140ffb 100644
--- a/drivers/devfreq/exynos/exynos_ppmu.c
+++ b/drivers/devfreq/exynos/exynos_ppmu.c
@@ -54,3 +54,63 @@ unsigned int exynos_ppmu_read(void __iomem *ppmu_base, unsigned int ch)
return total;
}
+
+void busfreq_mon_reset(struct busfreq_ppmu_data *ppmu_data)
+{
+ unsigned int i;
+
+ for (i = 0; i < ppmu_data->ppmu_end; i++) {
+ void __iomem *ppmu_base = ppmu_data->ppmu[i].hw_base;
+
+ /* Reset the performance and cycle counters */
+ exynos_ppmu_reset(ppmu_base);
+
+ /* Setup count registers to monitor read/write transactions */
+ ppmu_data->ppmu[i].event[PPMU_PMNCNT3] = RDWR_DATA_COUNT;
+ exynos_ppmu_setevent(ppmu_base, PPMU_PMNCNT3,
+ ppmu_data->ppmu[i].event[PPMU_PMNCNT3]);
+
+ exynos_ppmu_start(ppmu_base);
+ }
+}
+
+void exynos_read_ppmu(struct busfreq_ppmu_data *ppmu_data)
+{
+ int i, j;
+
+ for (i = 0; i < ppmu_data->ppmu_end; i++) {
+ void __iomem *ppmu_base = ppmu_data->ppmu[i].hw_base;
+
+ exynos_ppmu_stop(ppmu_base);
+
+ /* Update local data from PPMU */
+ ppmu_data->ppmu[i].ccnt = __raw_readl(ppmu_base + PPMU_CCNT);
+
+ for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
+ if (ppmu_data->ppmu[i].event[j] == 0)
+ ppmu_data->ppmu[i].count[j] = 0;
+ else
+ ppmu_data->ppmu[i].count[j] =
+ exynos_ppmu_read(ppmu_base, j);
+ }
+ }
+
+ busfreq_mon_reset(ppmu_data);
+}
+
+int exynos_get_busier_ppmu(struct busfreq_ppmu_data *ppmu_data)
+{
+ unsigned int count = 0;
+ int i, j, busy = 0;
+
+ for (i = 0; i < ppmu_data->ppmu_end; i++) {
+ for (j = PPMU_PMNCNT0; j < PPMU_PMNCNT_MAX; j++) {
+ if (ppmu_data->ppmu[i].count[j] > count) {
+ count = ppmu_data->ppmu[i].count[j];
+ busy = i;
+ }
+ }
+ }
+
+ return busy;
+}
diff --git a/drivers/devfreq/exynos/exynos_ppmu.h b/drivers/devfreq/exynos/exynos_ppmu.h
index 7dfb221eaccd..71f17ba3563c 100644
--- a/drivers/devfreq/exynos/exynos_ppmu.h
+++ b/drivers/devfreq/exynos/exynos_ppmu.h
@@ -69,10 +69,18 @@ struct exynos_ppmu {
bool count_overflow[PPMU_PMNCNT_MAX];
};
+struct busfreq_ppmu_data {
+ struct exynos_ppmu *ppmu;
+ int ppmu_end;
+};
+
void exynos_ppmu_reset(void __iomem *ppmu_base);
void exynos_ppmu_setevent(void __iomem *ppmu_base, unsigned int ch,
unsigned int evt);
void exynos_ppmu_start(void __iomem *ppmu_base);
void exynos_ppmu_stop(void __iomem *ppmu_base);
unsigned int exynos_ppmu_read(void __iomem *ppmu_base, unsigned int ch);
+void busfreq_mon_reset(struct busfreq_ppmu_data *ppmu_data);
+void exynos_read_ppmu(struct busfreq_ppmu_data *ppmu_data);
+int exynos_get_busier_ppmu(struct busfreq_ppmu_data *ppmu_data);
#endif /* __DEVFREQ_EXYNOS_PPMU_H */
diff --git a/drivers/firewire/Kconfig b/drivers/firewire/Kconfig
index 7a701a58bbf0..4199849e3758 100644
--- a/drivers/firewire/Kconfig
+++ b/drivers/firewire/Kconfig
@@ -1,5 +1,5 @@
menu "IEEE 1394 (FireWire) support"
- depends on PCI || BROKEN
+ depends on PCI || COMPILE_TEST
# firewire-core does not depend on PCI but is
# not useful without PCI controller driver
diff --git a/drivers/firewire/core.h b/drivers/firewire/core.h
index f477308b6e9c..e1480ff683d2 100644
--- a/drivers/firewire/core.h
+++ b/drivers/firewire/core.h
@@ -118,7 +118,6 @@ int fw_card_add(struct fw_card *card,
u32 max_receive, u32 link_speed, u64 guid);
void fw_core_remove_card(struct fw_card *card);
int fw_compute_block_crc(__be32 *block);
-void fw_schedule_bus_reset(struct fw_card *card, bool delayed, bool short_reset);
void fw_schedule_bm_work(struct fw_card *card, unsigned long delay);
/* -cdev */
diff --git a/drivers/firewire/net.c b/drivers/firewire/net.c
index 4af0a7bad7f2..c3986452194d 100644
--- a/drivers/firewire/net.c
+++ b/drivers/firewire/net.c
@@ -1462,8 +1462,8 @@ static int fwnet_probe(struct fw_unit *unit,
net = alloc_netdev(sizeof(*dev), "firewire%d", fwnet_init_dev);
if (net == NULL) {
- ret = -ENOMEM;
- goto out;
+ mutex_unlock(&fwnet_device_mutex);
+ return -ENOMEM;
}
allocated_netdev = true;
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index ce7a5812ae9d..57985410f12f 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -282,6 +282,7 @@ static char ohci_driver_name[] = KBUILD_MODNAME;
#define PCI_DEVICE_ID_TI_TSB82AA2 0x8025
#define PCI_DEVICE_ID_VIA_VT630X 0x3044
#define PCI_REV_ID_VIA_VT6306 0x46
+#define PCI_DEVICE_ID_VIA_VT6315 0x3403
#define QUIRK_CYCLE_TIMER 0x1
#define QUIRK_RESET_PACKET 0x2
@@ -334,6 +335,12 @@ static const struct {
{PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT630X, PCI_REV_ID_VIA_VT6306,
QUIRK_CYCLE_TIMER | QUIRK_IR_WAKE},
+ {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT6315, 0,
+ QUIRK_CYCLE_TIMER | QUIRK_NO_MSI},
+
+ {PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VT6315, PCI_ANY_ID,
+ 0},
+
{PCI_VENDOR_ID_VIA, PCI_ANY_ID, PCI_ANY_ID,
QUIRK_CYCLE_TIMER | QUIRK_NO_MSI},
};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
index 09312b877470..3d78144387ac 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
@@ -284,7 +284,7 @@ static struct exynos_drm_ippdrv *ipp_find_drv_by_handle(u32 prop_id)
/*
* This case is search ipp driver by prop_id handle.
* sometimes, ipp subsystem find driver by prop_id.
- * e.g PAUSE state, queue buf, command contro.
+ * e.g PAUSE state, queue buf, command control.
*/
list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n", count++, (int)ippdrv);
diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c
index 630f6e84fc01..2c1e4aad7da3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_backlight.c
+++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c
@@ -31,7 +31,6 @@
*/
#include <linux/backlight.h>
-#include <linux/acpi.h>
#include "nouveau_drm.h"
#include "nouveau_reg.h"
@@ -222,14 +221,6 @@ nouveau_backlight_init(struct drm_device *dev)
struct nouveau_device *device = nv_device(drm->device);
struct drm_connector *connector;
-#ifdef CONFIG_ACPI
- if (acpi_video_backlight_support()) {
- NV_INFO(drm, "ACPI backlight interface available, "
- "not registering our own\n");
- return 0;
- }
-#endif
-
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
if (connector->connector_type != DRM_MODE_CONNECTOR_LVDS &&
connector->connector_type != DRM_MODE_CONNECTOR_eDP)
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 7af9d0b5dea1..800c8b60f7a2 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -608,7 +608,10 @@ config HID_SAITEK
Support for Saitek devices that are not fully compliant with the
HID standard.
- Currently only supports the PS1000 controller.
+ Supported devices:
+ - PS1000 Dual Analog Pad
+ - R.A.T.7 Gaming Mouse
+ - M.M.O.7 Gaming Mouse
config HID_SAMSUNG
tristate "Samsung InfraRed remote control or keyboards"
@@ -657,6 +660,14 @@ config HID_SUNPLUS
---help---
Support for Sunplus wireless desktop.
+config HID_RMI
+ tristate "Synaptics RMI4 device support"
+ depends on HID
+ ---help---
+ Support for Synaptics RMI4 touchpads.
+ Say Y here if you have a Synaptics RMI4 touchpads over i2c-hid or usbhid
+ and want support for its special functionalities.
+
config HID_GREENASIA
tristate "GreenAsia (Product ID 0x12) game controller support"
depends on HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index fc712dde02a4..a6fa6baf368e 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -97,6 +97,7 @@ obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \
hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
hid-roccat-koneplus.o hid-roccat-konepure.o hid-roccat-kovaplus.o \
hid-roccat-lua.o hid-roccat-pyra.o hid-roccat-ryos.o hid-roccat-savu.o
+obj-$(CONFIG_HID_RMI) += hid-rmi.o
obj-$(CONFIG_HID_SAITEK) += hid-saitek.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index da52279de939..8ed66fd1ea87 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -779,6 +779,14 @@ static int hid_scan_report(struct hid_device *hid)
(hid->group == HID_GROUP_MULTITOUCH))
hid->group = HID_GROUP_MULTITOUCH_WIN_8;
+ /*
+ * Vendor specific handlings
+ */
+ if ((hid->vendor == USB_VENDOR_ID_SYNAPTICS) &&
+ (hid->group == HID_GROUP_GENERIC))
+ /* hid-rmi should take care of them, not hid-generic */
+ hid->group = HID_GROUP_RMI;
+
vfree(parser);
return 0;
}
@@ -842,7 +850,17 @@ struct hid_report *hid_validate_values(struct hid_device *hid,
* ->numbered being checked, which may not always be the case when
* drivers go to access report values.
*/
- report = hid->report_enum[type].report_id_hash[id];
+ if (id == 0) {
+ /*
+ * Validating on id 0 means we should examine the first
+ * report in the list.
+ */
+ report = list_entry(
+ hid->report_enum[type].report_list.next,
+ struct hid_report, list);
+ } else {
+ report = hid->report_enum[type].report_id_hash[id];
+ }
if (!report) {
hid_err(hid, "missing %s %u\n", hid_report_names[type], id);
return NULL;
@@ -1868,7 +1886,11 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK_PRO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) },
#endif
+#if IS_ENABLED(CONFIG_HID_SAITEK)
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7) },
+#endif
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) },
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 53b771d5683c..84c3cb15ccdd 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -165,6 +165,8 @@ static const struct hid_usage_entry hid_usage_table[] = {
{0, 0x53, "DeviceIndex"},
{0, 0x54, "ContactCount"},
{0, 0x55, "ContactMaximumNumber"},
+ {0, 0x5A, "SecondaryBarrelSwitch"},
+ {0, 0x5B, "TransducerSerialNumber"},
{ 15, 0, "PhysicalInterfaceDevice" },
{0, 0x00, "Undefined"},
{0, 0x01, "Physical_Interface_Device"},
@@ -272,6 +274,85 @@ static const struct hid_usage_entry hid_usage_table[] = {
{0, 0xAA, "Shared_Parameter_Blocks"},
{0, 0xAB, "Create_New_Effect_Report"},
{0, 0xAC, "RAM_Pool_Available"},
+ { 0x20, 0, "Sensor" },
+ { 0x20, 0x01, "Sensor" },
+ { 0x20, 0x10, "Biometric" },
+ { 0x20, 0x11, "BiometricHumanPresence" },
+ { 0x20, 0x12, "BiometricHumanProximity" },
+ { 0x20, 0x13, "BiometricHumanTouch" },
+ { 0x20, 0x20, "Electrical" },
+ { 0x20, 0x21, "ElectricalCapacitance" },
+ { 0x20, 0x22, "ElectricalCurrent" },
+ { 0x20, 0x23, "ElectricalPower" },
+ { 0x20, 0x24, "ElectricalInductance" },
+ { 0x20, 0x25, "ElectricalResistance" },
+ { 0x20, 0x26, "ElectricalVoltage" },
+ { 0x20, 0x27, "ElectricalPoteniometer" },
+ { 0x20, 0x28, "ElectricalFrequency" },
+ { 0x20, 0x29, "ElectricalPeriod" },
+ { 0x20, 0x30, "Environmental" },
+ { 0x20, 0x31, "EnvironmentalAtmosphericPressure" },
+ { 0x20, 0x32, "EnvironmentalHumidity" },
+ { 0x20, 0x33, "EnvironmentalTemperature" },
+ { 0x20, 0x34, "EnvironmentalWindDirection" },
+ { 0x20, 0x35, "EnvironmentalWindSpeed" },
+ { 0x20, 0x40, "Light" },
+ { 0x20, 0x41, "LightAmbientLight" },
+ { 0x20, 0x42, "LightConsumerInfrared" },
+ { 0x20, 0x50, "Location" },
+ { 0x20, 0x51, "LocationBroadcast" },
+ { 0x20, 0x52, "LocationDeadReckoning" },
+ { 0x20, 0x53, "LocationGPS" },
+ { 0x20, 0x54, "LocationLookup" },
+ { 0x20, 0x55, "LocationOther" },
+ { 0x20, 0x56, "LocationStatic" },
+ { 0x20, 0x57, "LocationTriangulation" },
+ { 0x20, 0x60, "Mechanical" },
+ { 0x20, 0x61, "MechanicalBooleanSwitch" },
+ { 0x20, 0x62, "MechanicalBooleanSwitchArray" },
+ { 0x20, 0x63, "MechanicalMultivalueSwitch" },
+ { 0x20, 0x64, "MechanicalForce" },
+ { 0x20, 0x65, "MechanicalPressure" },
+ { 0x20, 0x66, "MechanicalStrain" },
+ { 0x20, 0x67, "MechanicalWeight" },
+ { 0x20, 0x68, "MechanicalHapticVibrator" },
+ { 0x20, 0x69, "MechanicalHallEffectSwitch" },
+ { 0x20, 0x70, "Motion" },
+ { 0x20, 0x71, "MotionAccelerometer1D" },
+ { 0x20, 0x72, "MotionAccelerometer2D" },
+ { 0x20, 0x73, "MotionAccelerometer3D" },
+ { 0x20, 0x74, "MotionGyrometer1D" },
+ { 0x20, 0x75, "MotionGyrometer2D" },
+ { 0x20, 0x76, "MotionGyrometer3D" },
+ { 0x20, 0x77, "MotionMotionDetector" },
+ { 0x20, 0x78, "MotionSpeedometer" },
+ { 0x20, 0x79, "MotionAccelerometer" },
+ { 0x20, 0x7A, "MotionGyrometer" },
+ { 0x20, 0x80, "Orientation" },
+ { 0x20, 0x81, "OrientationCompass1D" },
+ { 0x20, 0x82, "OrientationCompass2D" },
+ { 0x20, 0x83, "OrientationCompass3D" },
+ { 0x20, 0x84, "OrientationInclinometer1D" },
+ { 0x20, 0x85, "OrientationInclinometer2D" },
+ { 0x20, 0x86, "OrientationInclinometer3D" },
+ { 0x20, 0x87, "OrientationDistance1D" },
+ { 0x20, 0x88, "OrientationDistance2D" },
+ { 0x20, 0x89, "OrientationDistance3D" },
+ { 0x20, 0x8A, "OrientationDeviceOrientation" },
+ { 0x20, 0x8B, "OrientationCompass" },
+ { 0x20, 0x8C, "OrientationInclinometer" },
+ { 0x20, 0x8D, "OrientationDistance" },
+ { 0x20, 0x90, "Scanner" },
+ { 0x20, 0x91, "ScannerBarcode" },
+ { 0x20, 0x91, "ScannerRFID" },
+ { 0x20, 0x91, "ScannerNFC" },
+ { 0x20, 0xA0, "Time" },
+ { 0x20, 0xA1, "TimeAlarmTimer" },
+ { 0x20, 0xA2, "TimeRealTimeClock" },
+ { 0x20, 0xE0, "Other" },
+ { 0x20, 0xE1, "OtherCustom" },
+ { 0x20, 0xE2, "OtherGeneric" },
+ { 0x20, 0xE3, "OtherGenericEnumerator" },
{ 0x84, 0, "Power Device" },
{ 0x84, 0x02, "PresentStatus" },
{ 0x84, 0x03, "ChangeStatus" },
@@ -855,6 +936,16 @@ static const char *keys[KEY_MAX + 1] = {
[KEY_KBDILLUMDOWN] = "KbdIlluminationDown",
[KEY_KBDILLUMUP] = "KbdIlluminationUp",
[KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
+ [KEY_BUTTONCONFIG] = "ButtonConfig",
+ [KEY_TASKMANAGER] = "TaskManager",
+ [KEY_JOURNAL] = "Journal",
+ [KEY_CONTROLPANEL] = "ControlPanel",
+ [KEY_APPSELECT] = "AppSelect",
+ [KEY_SCREENSAVER] = "ScreenSaver",
+ [KEY_VOICECOMMAND] = "VoiceCommand",
+ [KEY_BRIGHTNESS_MIN] = "BrightnessMin",
+ [KEY_BRIGHTNESS_MAX] = "BrightnessMax",
+ [KEY_BRIGHTNESS_AUTO] = "BrightnessAuto",
};
static const char *relatives[REL_MAX + 1] = {
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 34bb2205d2ea..6d00bb9366fa 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -463,6 +463,7 @@
#define USB_VENDOR_ID_STM_0 0x0483
#define USB_DEVICE_ID_STM_HID_SENSOR 0x91d1
+#define USB_DEVICE_ID_STM_HID_SENSOR_1 0x9100
#define USB_VENDOR_ID_ION 0x15e4
#define USB_DEVICE_ID_ICADE 0x0132
@@ -633,6 +634,9 @@
#define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713
#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K 0x0730
#define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c
+#define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799
+#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7
+#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9
#define USB_VENDOR_ID_MOJO 0x8282
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
@@ -764,11 +768,16 @@
#define USB_VENDOR_ID_SAITEK 0x06a3
#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
#define USB_DEVICE_ID_SAITEK_PS1000 0x0621
+#define USB_DEVICE_ID_SAITEK_RAT7 0x0cd7
+#define USB_DEVICE_ID_SAITEK_MMO7 0x0cd0
#define USB_VENDOR_ID_SAMSUNG 0x0419
#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600
+#define USB_VENDOR_ID_SEMICO 0x1a2c
+#define USB_DEVICE_ID_SEMICO_USB_KEYKOARD 0x0023
+
#define USB_VENDOR_ID_SENNHEISER 0x1395
#define USB_DEVICE_ID_SENNHEISER_BTD500USB 0x002c
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index e7e8b19a9284..2619f7f4517a 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -684,9 +684,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
break;
case 0x46: /* TabletPick */
+ case 0x5a: /* SecondaryBarrelSwitch */
map_key_clear(BTN_STYLUS2);
break;
+ case 0x5b: /* TransducerSerialNumber */
+ set_bit(MSC_SERIAL, input->mscbit);
+ break;
+
default: goto unknown;
}
break;
@@ -721,6 +726,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x06c: map_key_clear(KEY_YELLOW); break;
case 0x06d: map_key_clear(KEY_ZOOM); break;
+ case 0x06f: map_key_clear(KEY_BRIGHTNESSUP); break;
+ case 0x070: map_key_clear(KEY_BRIGHTNESSDOWN); break;
+ case 0x072: map_key_clear(KEY_BRIGHTNESS_TOGGLE); break;
+ case 0x073: map_key_clear(KEY_BRIGHTNESS_MIN); break;
+ case 0x074: map_key_clear(KEY_BRIGHTNESS_MAX); break;
+ case 0x075: map_key_clear(KEY_BRIGHTNESS_AUTO); break;
+
case 0x082: map_key_clear(KEY_VIDEO_NEXT); break;
case 0x083: map_key_clear(KEY_LAST); break;
case 0x084: map_key_clear(KEY_ENTER); break;
@@ -761,6 +773,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x0bf: map_key_clear(KEY_SLOW); break;
case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break;
+ case 0x0cf: map_key_clear(KEY_VOICECOMMAND); break;
case 0x0e0: map_abs_clear(ABS_VOLUME); break;
case 0x0e2: map_key_clear(KEY_MUTE); break;
case 0x0e5: map_key_clear(KEY_BASSBOOST); break;
@@ -768,6 +781,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break;
case 0x0f5: map_key_clear(KEY_SLOW); break;
+ case 0x181: map_key_clear(KEY_BUTTONCONFIG); break;
case 0x182: map_key_clear(KEY_BOOKMARKS); break;
case 0x183: map_key_clear(KEY_CONFIG); break;
case 0x184: map_key_clear(KEY_WORDPROCESSOR); break;
@@ -781,6 +795,8 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x18c: map_key_clear(KEY_VOICEMAIL); break;
case 0x18d: map_key_clear(KEY_ADDRESSBOOK); break;
case 0x18e: map_key_clear(KEY_CALENDAR); break;
+ case 0x18f: map_key_clear(KEY_TASKMANAGER); break;
+ case 0x190: map_key_clear(KEY_JOURNAL); break;
case 0x191: map_key_clear(KEY_FINANCE); break;
case 0x192: map_key_clear(KEY_CALC); break;
case 0x193: map_key_clear(KEY_PLAYER); break;
@@ -789,12 +805,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x199: map_key_clear(KEY_CHAT); break;
case 0x19c: map_key_clear(KEY_LOGOFF); break;
case 0x19e: map_key_clear(KEY_COFFEE); break;
+ case 0x19f: map_key_clear(KEY_CONTROLPANEL); break;
+ case 0x1a2: map_key_clear(KEY_APPSELECT); break;
case 0x1a3: map_key_clear(KEY_NEXT); break;
case 0x1a4: map_key_clear(KEY_PREVIOUS); break;
case 0x1a6: map_key_clear(KEY_HELP); break;
case 0x1a7: map_key_clear(KEY_DOCUMENTS); break;
case 0x1ab: map_key_clear(KEY_SPELLCHECK); break;
case 0x1ae: map_key_clear(KEY_KEYBOARD); break;
+ case 0x1b1: map_key_clear(KEY_SCREENSAVER); break;
case 0x1b4: map_key_clear(KEY_FILE); break;
case 0x1b6: map_key_clear(KEY_IMAGES); break;
case 0x1b7: map_key_clear(KEY_AUDIO); break;
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
new file mode 100644
index 000000000000..2451c7e5febd
--- /dev/null
+++ b/drivers/hid/hid-rmi.c
@@ -0,0 +1,920 @@
+/*
+ * Copyright (c) 2013 Andrew Duggan <aduggan@synaptics.com>
+ * Copyright (c) 2013 Synaptics Incorporated
+ * Copyright (c) 2014 Benjamin Tissoires <benjamin.tissoires@gmail.com>
+ * Copyright (c) 2014 Red Hat, Inc
+ *
+ * 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/kernel.h>
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include "hid-ids.h"
+
+#define RMI_MOUSE_REPORT_ID 0x01 /* Mouse emulation Report */
+#define RMI_WRITE_REPORT_ID 0x09 /* Output Report */
+#define RMI_READ_ADDR_REPORT_ID 0x0a /* Output Report */
+#define RMI_READ_DATA_REPORT_ID 0x0b /* Input Report */
+#define RMI_ATTN_REPORT_ID 0x0c /* Input Report */
+#define RMI_SET_RMI_MODE_REPORT_ID 0x0f /* Feature Report */
+
+/* flags */
+#define RMI_READ_REQUEST_PENDING BIT(0)
+#define RMI_READ_DATA_PENDING BIT(1)
+#define RMI_STARTED BIT(2)
+
+enum rmi_mode_type {
+ RMI_MODE_OFF = 0,
+ RMI_MODE_ATTN_REPORTS = 1,
+ RMI_MODE_NO_PACKED_ATTN_REPORTS = 2,
+};
+
+struct rmi_function {
+ unsigned page; /* page of the function */
+ u16 query_base_addr; /* base address for queries */
+ u16 command_base_addr; /* base address for commands */
+ u16 control_base_addr; /* base address for controls */
+ u16 data_base_addr; /* base address for datas */
+ unsigned int interrupt_base; /* cross-function interrupt number
+ * (uniq in the device)*/
+ unsigned int interrupt_count; /* number of interrupts */
+ unsigned int report_size; /* size of a report */
+ unsigned long irq_mask; /* mask of the interrupts
+ * (to be applied against ATTN IRQ) */
+};
+
+/**
+ * struct rmi_data - stores information for hid communication
+ *
+ * @page_mutex: Locks current page to avoid changing pages in unexpected ways.
+ * @page: Keeps track of the current virtual page
+ *
+ * @wait: Used for waiting for read data
+ *
+ * @writeReport: output buffer when writing RMI registers
+ * @readReport: input buffer when reading RMI registers
+ *
+ * @input_report_size: size of an input report (advertised by HID)
+ * @output_report_size: size of an output report (advertised by HID)
+ *
+ * @flags: flags for the current device (started, reading, etc...)
+ *
+ * @f11: placeholder of internal RMI function F11 description
+ * @f30: placeholder of internal RMI function F30 description
+ *
+ * @max_fingers: maximum finger count reported by the device
+ * @max_x: maximum x value reported by the device
+ * @max_y: maximum y value reported by the device
+ *
+ * @gpio_led_count: count of GPIOs + LEDs reported by F30
+ * @button_count: actual physical buttons count
+ * @button_mask: button mask used to decode GPIO ATTN reports
+ * @button_state_mask: pull state of the buttons
+ *
+ * @input: pointer to the kernel input device
+ *
+ * @reset_work: worker which will be called in case of a mouse report
+ * @hdev: pointer to the struct hid_device
+ */
+struct rmi_data {
+ struct mutex page_mutex;
+ int page;
+
+ wait_queue_head_t wait;
+
+ u8 *writeReport;
+ u8 *readReport;
+
+ int input_report_size;
+ int output_report_size;
+
+ unsigned long flags;
+
+ struct rmi_function f11;
+ struct rmi_function f30;
+
+ unsigned int max_fingers;
+ unsigned int max_x;
+ unsigned int max_y;
+ unsigned int x_size_mm;
+ unsigned int y_size_mm;
+
+ unsigned int gpio_led_count;
+ unsigned int button_count;
+ unsigned long button_mask;
+ unsigned long button_state_mask;
+
+ struct input_dev *input;
+
+ struct work_struct reset_work;
+ struct hid_device *hdev;
+};
+
+#define RMI_PAGE(addr) (((addr) >> 8) & 0xff)
+
+static int rmi_write_report(struct hid_device *hdev, u8 *report, int len);
+
+/**
+ * rmi_set_page - Set RMI page
+ * @hdev: The pointer to the hid_device struct
+ * @page: The new page address.
+ *
+ * RMI devices have 16-bit addressing, but some of the physical
+ * implementations (like SMBus) only have 8-bit addressing. So RMI implements
+ * a page address at 0xff of every page so we can reliable page addresses
+ * every 256 registers.
+ *
+ * The page_mutex lock must be held when this function is entered.
+ *
+ * Returns zero on success, non-zero on failure.
+ */
+static int rmi_set_page(struct hid_device *hdev, u8 page)
+{
+ struct rmi_data *data = hid_get_drvdata(hdev);
+ int retval;
+
+ data->writeReport[0] = RMI_WRITE_REPORT_ID;
+ data->writeReport[1] = 1;
+ data->writeReport[2] = 0xFF;
+ data->writeReport[4] = page;
+
+ retval = rmi_write_report(hdev, data->writeReport,
+ data->output_report_size);
+ if (retval != data->output_report_size) {
+ dev_err(&hdev->dev,
+ "%s: set page failed: %d.", __func__, retval);
+ return retval;
+ }
+
+ data->page = page;
+ return 0;
+}
+
+static int rmi_set_mode(struct hid_device *hdev, u8 mode)
+{
+ int ret;
+ u8 txbuf[2] = {RMI_SET_RMI_MODE_REPORT_ID, mode};
+
+ ret = hid_hw_raw_request(hdev, RMI_SET_RMI_MODE_REPORT_ID, txbuf,
+ sizeof(txbuf), HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "unable to set rmi mode to %d (%d)\n", mode,
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rmi_write_report(struct hid_device *hdev, u8 *report, int len)
+{
+ int ret;
+
+ ret = hid_hw_output_report(hdev, (void *)report, len);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "failed to write hid report (%d)\n", ret);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int rmi_read_block(struct hid_device *hdev, u16 addr, void *buf,
+ const int len)
+{
+ struct rmi_data *data = hid_get_drvdata(hdev);
+ int ret;
+ int bytes_read;
+ int bytes_needed;
+ int retries;
+ int read_input_count;
+
+ mutex_lock(&data->page_mutex);
+
+ if (RMI_PAGE(addr) != data->page) {
+ ret = rmi_set_page(hdev, RMI_PAGE(addr));
+ if (ret < 0)
+ goto exit;
+ }
+
+ for (retries = 5; retries > 0; retries--) {
+ data->writeReport[0] = RMI_READ_ADDR_REPORT_ID;
+ data->writeReport[1] = 0; /* old 1 byte read count */
+ data->writeReport[2] = addr & 0xFF;
+ data->writeReport[3] = (addr >> 8) & 0xFF;
+ data->writeReport[4] = len & 0xFF;
+ data->writeReport[5] = (len >> 8) & 0xFF;
+
+ set_bit(RMI_READ_REQUEST_PENDING, &data->flags);
+
+ ret = rmi_write_report(hdev, data->writeReport,
+ data->output_report_size);
+ if (ret != data->output_report_size) {
+ clear_bit(RMI_READ_REQUEST_PENDING, &data->flags);
+ dev_err(&hdev->dev,
+ "failed to write request output report (%d)\n",
+ ret);
+ goto exit;
+ }
+
+ bytes_read = 0;
+ bytes_needed = len;
+ while (bytes_read < len) {
+ if (!wait_event_timeout(data->wait,
+ test_bit(RMI_READ_DATA_PENDING, &data->flags),
+ msecs_to_jiffies(1000))) {
+ hid_warn(hdev, "%s: timeout elapsed\n",
+ __func__);
+ ret = -EAGAIN;
+ break;
+ }
+
+ read_input_count = data->readReport[1];
+ memcpy(buf + bytes_read, &data->readReport[2],
+ read_input_count < bytes_needed ?
+ read_input_count : bytes_needed);
+
+ bytes_read += read_input_count;
+ bytes_needed -= read_input_count;
+ clear_bit(RMI_READ_DATA_PENDING, &data->flags);
+ }
+
+ if (ret >= 0) {
+ ret = 0;
+ break;
+ }
+ }
+
+exit:
+ clear_bit(RMI_READ_REQUEST_PENDING, &data->flags);
+ mutex_unlock(&data->page_mutex);
+ return ret;
+}
+
+static inline int rmi_read(struct hid_device *hdev, u16 addr, void *buf)
+{
+ return rmi_read_block(hdev, addr, buf, 1);
+}
+
+static void rmi_f11_process_touch(struct rmi_data *hdata, int slot,
+ u8 finger_state, u8 *touch_data)
+{
+ int x, y, wx, wy;
+ int wide, major, minor;
+ int z;
+
+ input_mt_slot(hdata->input, slot);
+ input_mt_report_slot_state(hdata->input, MT_TOOL_FINGER,
+ finger_state == 0x01);
+ if (finger_state == 0x01) {
+ x = (touch_data[0] << 4) | (touch_data[2] & 0x0F);
+ y = (touch_data[1] << 4) | (touch_data[2] >> 4);
+ wx = touch_data[3] & 0x0F;
+ wy = touch_data[3] >> 4;
+ wide = (wx > wy);
+ major = max(wx, wy);
+ minor = min(wx, wy);
+ z = touch_data[4];
+
+ /* y is inverted */
+ y = hdata->max_y - y;
+
+ input_event(hdata->input, EV_ABS, ABS_MT_POSITION_X, x);
+ input_event(hdata->input, EV_ABS, ABS_MT_POSITION_Y, y);
+ input_event(hdata->input, EV_ABS, ABS_MT_ORIENTATION, wide);
+ input_event(hdata->input, EV_ABS, ABS_MT_PRESSURE, z);
+ input_event(hdata->input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
+ input_event(hdata->input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
+ }
+}
+
+static void rmi_reset_work(struct work_struct *work)
+{
+ struct rmi_data *hdata = container_of(work, struct rmi_data,
+ reset_work);
+
+ /* switch the device to RMI if we receive a generic mouse report */
+ rmi_set_mode(hdata->hdev, RMI_MODE_ATTN_REPORTS);
+}
+
+static inline int rmi_schedule_reset(struct hid_device *hdev)
+{
+ struct rmi_data *hdata = hid_get_drvdata(hdev);
+ return schedule_work(&hdata->reset_work);
+}
+
+static int rmi_f11_input_event(struct hid_device *hdev, u8 irq, u8 *data,
+ int size)
+{
+ struct rmi_data *hdata = hid_get_drvdata(hdev);
+ int offset;
+ int i;
+
+ if (size < hdata->f11.report_size)
+ return 0;
+
+ if (!(irq & hdata->f11.irq_mask))
+ return 0;
+
+ offset = (hdata->max_fingers >> 2) + 1;
+ for (i = 0; i < hdata->max_fingers; i++) {
+ int fs_byte_position = i >> 2;
+ int fs_bit_position = (i & 0x3) << 1;
+ int finger_state = (data[fs_byte_position] >> fs_bit_position) &
+ 0x03;
+
+ rmi_f11_process_touch(hdata, i, finger_state,
+ &data[offset + 5 * i]);
+ }
+ input_mt_sync_frame(hdata->input);
+ input_sync(hdata->input);
+ return hdata->f11.report_size;
+}
+
+static int rmi_f30_input_event(struct hid_device *hdev, u8 irq, u8 *data,
+ int size)
+{
+ struct rmi_data *hdata = hid_get_drvdata(hdev);
+ int i;
+ int button = 0;
+ bool value;
+
+ if (!(irq & hdata->f30.irq_mask))
+ return 0;
+
+ for (i = 0; i < hdata->gpio_led_count; i++) {
+ if (test_bit(i, &hdata->button_mask)) {
+ value = (data[i / 8] >> (i & 0x07)) & BIT(0);
+ if (test_bit(i, &hdata->button_state_mask))
+ value = !value;
+ input_event(hdata->input, EV_KEY, BTN_LEFT + button++,
+ value);
+ }
+ }
+ return hdata->f30.report_size;
+}
+
+static int rmi_input_event(struct hid_device *hdev, u8 *data, int size)
+{
+ struct rmi_data *hdata = hid_get_drvdata(hdev);
+ unsigned long irq_mask = 0;
+ unsigned index = 2;
+
+ if (!(test_bit(RMI_STARTED, &hdata->flags)))
+ return 0;
+
+ irq_mask |= hdata->f11.irq_mask;
+ irq_mask |= hdata->f30.irq_mask;
+
+ if (data[1] & ~irq_mask)
+ hid_warn(hdev, "unknown intr source:%02lx %s:%d\n",
+ data[1] & ~irq_mask, __FILE__, __LINE__);
+
+ if (hdata->f11.interrupt_base < hdata->f30.interrupt_base) {
+ index += rmi_f11_input_event(hdev, data[1], &data[index],
+ size - index);
+ index += rmi_f30_input_event(hdev, data[1], &data[index],
+ size - index);
+ } else {
+ index += rmi_f30_input_event(hdev, data[1], &data[index],
+ size - index);
+ index += rmi_f11_input_event(hdev, data[1], &data[index],
+ size - index);
+ }
+
+ return 1;
+}
+
+static int rmi_read_data_event(struct hid_device *hdev, u8 *data, int size)
+{
+ struct rmi_data *hdata = hid_get_drvdata(hdev);
+
+ if (!test_bit(RMI_READ_REQUEST_PENDING, &hdata->flags)) {
+ hid_err(hdev, "no read request pending\n");
+ return 0;
+ }
+
+ memcpy(hdata->readReport, data, size < hdata->input_report_size ?
+ size : hdata->input_report_size);
+ set_bit(RMI_READ_DATA_PENDING, &hdata->flags);
+ wake_up(&hdata->wait);
+
+ return 1;
+}
+
+static int rmi_raw_event(struct hid_device *hdev,
+ struct hid_report *report, u8 *data, int size)
+{
+ switch (data[0]) {
+ case RMI_READ_DATA_REPORT_ID:
+ return rmi_read_data_event(hdev, data, size);
+ case RMI_ATTN_REPORT_ID:
+ return rmi_input_event(hdev, data, size);
+ case RMI_MOUSE_REPORT_ID:
+ rmi_schedule_reset(hdev);
+ break;
+ }
+
+ return 0;
+}
+
+static int rmi_post_reset(struct hid_device *hdev)
+{
+ return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
+}
+
+static int rmi_post_resume(struct hid_device *hdev)
+{
+ return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
+}
+
+#define RMI4_MAX_PAGE 0xff
+#define RMI4_PAGE_SIZE 0x0100
+
+#define PDT_START_SCAN_LOCATION 0x00e9
+#define PDT_END_SCAN_LOCATION 0x0005
+#define RMI4_END_OF_PDT(id) ((id) == 0x00 || (id) == 0xff)
+
+struct pdt_entry {
+ u8 query_base_addr:8;
+ u8 command_base_addr:8;
+ u8 control_base_addr:8;
+ u8 data_base_addr:8;
+ u8 interrupt_source_count:3;
+ u8 bits3and4:2;
+ u8 function_version:2;
+ u8 bit7:1;
+ u8 function_number:8;
+} __attribute__((__packed__));
+
+static inline unsigned long rmi_gen_mask(unsigned irq_base, unsigned irq_count)
+{
+ return GENMASK(irq_count + irq_base - 1, irq_base);
+}
+
+static void rmi_register_function(struct rmi_data *data,
+ struct pdt_entry *pdt_entry, int page, unsigned interrupt_count)
+{
+ struct rmi_function *f = NULL;
+ u16 page_base = page << 8;
+
+ switch (pdt_entry->function_number) {
+ case 0x11:
+ f = &data->f11;
+ break;
+ case 0x30:
+ f = &data->f30;
+ break;
+ }
+
+ if (f) {
+ f->page = page;
+ f->query_base_addr = page_base | pdt_entry->query_base_addr;
+ f->command_base_addr = page_base | pdt_entry->command_base_addr;
+ f->control_base_addr = page_base | pdt_entry->control_base_addr;
+ f->data_base_addr = page_base | pdt_entry->data_base_addr;
+ f->interrupt_base = interrupt_count;
+ f->interrupt_count = pdt_entry->interrupt_source_count;
+ f->irq_mask = rmi_gen_mask(f->interrupt_base,
+ f->interrupt_count);
+ }
+}
+
+static int rmi_scan_pdt(struct hid_device *hdev)
+{
+ struct rmi_data *data = hid_get_drvdata(hdev);
+ struct pdt_entry entry;
+ int page;
+ bool page_has_function;
+ int i;
+ int retval;
+ int interrupt = 0;
+ u16 page_start, pdt_start , pdt_end;
+
+ hid_info(hdev, "Scanning PDT...\n");
+
+ for (page = 0; (page <= RMI4_MAX_PAGE); page++) {
+ page_start = RMI4_PAGE_SIZE * page;
+ pdt_start = page_start + PDT_START_SCAN_LOCATION;
+ pdt_end = page_start + PDT_END_SCAN_LOCATION;
+
+ page_has_function = false;
+ for (i = pdt_start; i >= pdt_end; i -= sizeof(entry)) {
+ retval = rmi_read_block(hdev, i, &entry, sizeof(entry));
+ if (retval) {
+ hid_err(hdev,
+ "Read of PDT entry at %#06x failed.\n",
+ i);
+ goto error_exit;
+ }
+
+ if (RMI4_END_OF_PDT(entry.function_number))
+ break;
+
+ page_has_function = true;
+
+ hid_info(hdev, "Found F%02X on page %#04x\n",
+ entry.function_number, page);
+
+ rmi_register_function(data, &entry, page, interrupt);
+ interrupt += entry.interrupt_source_count;
+ }
+
+ if (!page_has_function)
+ break;
+ }
+
+ hid_info(hdev, "%s: Done with PDT scan.\n", __func__);
+ retval = 0;
+
+error_exit:
+ return retval;
+}
+
+static int rmi_populate_f11(struct hid_device *hdev)
+{
+ struct rmi_data *data = hid_get_drvdata(hdev);
+ u8 buf[20];
+ int ret;
+ bool has_query9;
+ bool has_query10;
+ bool has_query11;
+ bool has_query12;
+ bool has_physical_props;
+ unsigned x_size, y_size;
+ u16 query12_offset;
+
+ if (!data->f11.query_base_addr) {
+ hid_err(hdev, "No 2D sensor found, giving up.\n");
+ return -ENODEV;
+ }
+
+ /* query 0 contains some useful information */
+ ret = rmi_read(hdev, data->f11.query_base_addr, buf);
+ if (ret) {
+ hid_err(hdev, "can not get query 0: %d.\n", ret);
+ return ret;
+ }
+ has_query9 = !!(buf[0] & BIT(3));
+ has_query11 = !!(buf[0] & BIT(4));
+ has_query12 = !!(buf[0] & BIT(5));
+
+ /* query 1 to get the max number of fingers */
+ ret = rmi_read(hdev, data->f11.query_base_addr + 1, buf);
+ if (ret) {
+ hid_err(hdev, "can not get NumberOfFingers: %d.\n", ret);
+ return ret;
+ }
+ data->max_fingers = (buf[0] & 0x07) + 1;
+ if (data->max_fingers > 5)
+ data->max_fingers = 10;
+
+ data->f11.report_size = data->max_fingers * 5 +
+ DIV_ROUND_UP(data->max_fingers, 4);
+
+ if (!(buf[0] & BIT(4))) {
+ hid_err(hdev, "No absolute events, giving up.\n");
+ return -ENODEV;
+ }
+
+ /* query 8 to find out if query 10 exists */
+ ret = rmi_read(hdev, data->f11.query_base_addr + 8, buf);
+ if (ret) {
+ hid_err(hdev, "can not read gesture information: %d.\n", ret);
+ return ret;
+ }
+ has_query10 = !!(buf[0] & BIT(2));
+
+ /*
+ * At least 8 queries are guaranteed to be present in F11
+ * +1 for query12.
+ */
+ query12_offset = 9;
+
+ if (has_query9)
+ ++query12_offset;
+
+ if (has_query10)
+ ++query12_offset;
+
+ if (has_query11)
+ ++query12_offset;
+
+ /* query 12 to know if the physical properties are reported */
+ if (has_query12) {
+ ret = rmi_read(hdev, data->f11.query_base_addr
+ + query12_offset, buf);
+ if (ret) {
+ hid_err(hdev, "can not get query 12: %d.\n", ret);
+ return ret;
+ }
+ has_physical_props = !!(buf[0] & BIT(5));
+
+ if (has_physical_props) {
+ ret = rmi_read_block(hdev,
+ data->f11.query_base_addr
+ + query12_offset + 1, buf, 4);
+ if (ret) {
+ hid_err(hdev, "can not read query 15-18: %d.\n",
+ ret);
+ return ret;
+ }
+
+ x_size = buf[0] | (buf[1] << 8);
+ y_size = buf[2] | (buf[3] << 8);
+
+ data->x_size_mm = DIV_ROUND_CLOSEST(x_size, 10);
+ data->y_size_mm = DIV_ROUND_CLOSEST(y_size, 10);
+
+ hid_info(hdev, "%s: size in mm: %d x %d\n",
+ __func__, data->x_size_mm, data->y_size_mm);
+ }
+ }
+
+ /*
+ * retrieve the ctrl registers
+ * the ctrl register has a size of 20 but a fw bug split it into 16 + 4,
+ * and there is no way to know if the first 20 bytes are here or not.
+ * We use only the first 10 bytes, so get only them.
+ */
+ ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, 10);
+ if (ret) {
+ hid_err(hdev, "can not read ctrl block of size 10: %d.\n", ret);
+ return ret;
+ }
+
+ data->max_x = buf[6] | (buf[7] << 8);
+ data->max_y = buf[8] | (buf[9] << 8);
+
+ return 0;
+}
+
+static int rmi_populate_f30(struct hid_device *hdev)
+{
+ struct rmi_data *data = hid_get_drvdata(hdev);
+ u8 buf[20];
+ int ret;
+ bool has_gpio, has_led;
+ unsigned bytes_per_ctrl;
+ u8 ctrl2_addr;
+ int ctrl2_3_length;
+ int i;
+
+ /* function F30 is for physical buttons */
+ if (!data->f30.query_base_addr) {
+ hid_err(hdev, "No GPIO/LEDs found, giving up.\n");
+ return -ENODEV;
+ }
+
+ ret = rmi_read_block(hdev, data->f30.query_base_addr, buf, 2);
+ if (ret) {
+ hid_err(hdev, "can not get F30 query registers: %d.\n", ret);
+ return ret;
+ }
+
+ has_gpio = !!(buf[0] & BIT(3));
+ has_led = !!(buf[0] & BIT(2));
+ data->gpio_led_count = buf[1] & 0x1f;
+
+ /* retrieve ctrl 2 & 3 registers */
+ bytes_per_ctrl = (data->gpio_led_count + 7) / 8;
+ /* Ctrl0 is present only if both has_gpio and has_led are set*/
+ ctrl2_addr = (has_gpio && has_led) ? bytes_per_ctrl : 0;
+ /* Ctrl1 is always be present */
+ ctrl2_addr += bytes_per_ctrl;
+ ctrl2_3_length = 2 * bytes_per_ctrl;
+
+ data->f30.report_size = bytes_per_ctrl;
+
+ ret = rmi_read_block(hdev, data->f30.control_base_addr + ctrl2_addr,
+ buf, ctrl2_3_length);
+ if (ret) {
+ hid_err(hdev, "can not read ctrl 2&3 block of size %d: %d.\n",
+ ctrl2_3_length, ret);
+ return ret;
+ }
+
+ for (i = 0; i < data->gpio_led_count; i++) {
+ int byte_position = i >> 3;
+ int bit_position = i & 0x07;
+ u8 dir_byte = buf[byte_position];
+ u8 data_byte = buf[byte_position + bytes_per_ctrl];
+ bool dir = (dir_byte >> bit_position) & BIT(0);
+ bool dat = (data_byte >> bit_position) & BIT(0);
+
+ if (dir == 0) {
+ /* input mode */
+ if (dat) {
+ /* actual buttons have pull up resistor */
+ data->button_count++;
+ set_bit(i, &data->button_mask);
+ set_bit(i, &data->button_state_mask);
+ }
+ }
+
+ }
+
+ return 0;
+}
+
+static int rmi_populate(struct hid_device *hdev)
+{
+ int ret;
+
+ ret = rmi_scan_pdt(hdev);
+ if (ret) {
+ hid_err(hdev, "PDT scan failed with code %d.\n", ret);
+ return ret;
+ }
+
+ ret = rmi_populate_f11(hdev);
+ if (ret) {
+ hid_err(hdev, "Error while initializing F11 (%d).\n", ret);
+ return ret;
+ }
+
+ ret = rmi_populate_f30(hdev);
+ if (ret)
+ hid_warn(hdev, "Error while initializing F30 (%d).\n", ret);
+
+ return 0;
+}
+
+static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
+{
+ struct rmi_data *data = hid_get_drvdata(hdev);
+ struct input_dev *input = hi->input;
+ int ret;
+ int res_x, res_y, i;
+
+ data->input = input;
+
+ hid_dbg(hdev, "Opening low level driver\n");
+ ret = hid_hw_open(hdev);
+ if (ret)
+ return;
+
+ /* Allow incoming hid reports */
+ hid_device_io_start(hdev);
+
+ ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "failed to set rmi mode\n");
+ goto exit;
+ }
+
+ ret = rmi_set_page(hdev, 0);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "failed to set page select to 0.\n");
+ goto exit;
+ }
+
+ ret = rmi_populate(hdev);
+ if (ret)
+ goto exit;
+
+ __set_bit(EV_ABS, input->evbit);
+ input_set_abs_params(input, ABS_MT_POSITION_X, 1, data->max_x, 0, 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, 1, data->max_y, 0, 0);
+
+ if (data->x_size_mm && data->y_size_mm) {
+ res_x = (data->max_x - 1) / data->x_size_mm;
+ res_y = (data->max_y - 1) / data->y_size_mm;
+
+ input_abs_set_res(input, ABS_MT_POSITION_X, res_x);
+ input_abs_set_res(input, ABS_MT_POSITION_Y, res_y);
+ }
+
+ input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0);
+ input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0);
+ input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0);
+ input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0);
+
+ input_mt_init_slots(input, data->max_fingers, INPUT_MT_POINTER);
+
+ if (data->button_count) {
+ __set_bit(EV_KEY, input->evbit);
+ for (i = 0; i < data->button_count; i++)
+ __set_bit(BTN_LEFT + i, input->keybit);
+
+ if (data->button_count == 1)
+ __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+ }
+
+ set_bit(RMI_STARTED, &data->flags);
+
+exit:
+ hid_device_io_stop(hdev);
+ hid_hw_close(hdev);
+}
+
+static int rmi_input_mapping(struct hid_device *hdev,
+ struct hid_input *hi, struct hid_field *field,
+ struct hid_usage *usage, unsigned long **bit, int *max)
+{
+ /* we want to make HID ignore the advertised HID collection */
+ return -1;
+}
+
+static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ struct rmi_data *data = NULL;
+ int ret;
+ size_t alloc_size;
+
+ data = devm_kzalloc(&hdev->dev, sizeof(struct rmi_data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ INIT_WORK(&data->reset_work, rmi_reset_work);
+ data->hdev = hdev;
+
+ hid_set_drvdata(hdev, data);
+
+ hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "parse failed\n");
+ return ret;
+ }
+
+ data->input_report_size = (hdev->report_enum[HID_INPUT_REPORT]
+ .report_id_hash[RMI_ATTN_REPORT_ID]->size >> 3)
+ + 1 /* report id */;
+ data->output_report_size = (hdev->report_enum[HID_OUTPUT_REPORT]
+ .report_id_hash[RMI_WRITE_REPORT_ID]->size >> 3)
+ + 1 /* report id */;
+
+ alloc_size = data->output_report_size + data->input_report_size;
+
+ data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL);
+ if (!data->writeReport) {
+ ret = -ENOMEM;
+ return ret;
+ }
+
+ data->readReport = data->writeReport + data->output_report_size;
+
+ init_waitqueue_head(&data->wait);
+
+ mutex_init(&data->page_mutex);
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ return ret;
+ }
+
+ if (!test_bit(RMI_STARTED, &data->flags)) {
+ hid_hw_stop(hdev);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void rmi_remove(struct hid_device *hdev)
+{
+ struct rmi_data *hdata = hid_get_drvdata(hdev);
+
+ clear_bit(RMI_STARTED, &hdata->flags);
+
+ hid_hw_stop(hdev);
+}
+
+static const struct hid_device_id rmi_id[] = {
+ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, rmi_id);
+
+static struct hid_driver rmi_driver = {
+ .name = "hid-rmi",
+ .id_table = rmi_id,
+ .probe = rmi_probe,
+ .remove = rmi_remove,
+ .raw_event = rmi_raw_event,
+ .input_mapping = rmi_input_mapping,
+ .input_configured = rmi_input_configured,
+#ifdef CONFIG_PM
+ .resume = rmi_post_resume,
+ .reset_resume = rmi_post_reset,
+#endif
+};
+
+module_hid_driver(rmi_driver);
+
+MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>");
+MODULE_DESCRIPTION("RMI HID driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-saitek.c b/drivers/hid/hid-saitek.c
index 37961c7e397d..69cca1476a0c 100644
--- a/drivers/hid/hid-saitek.c
+++ b/drivers/hid/hid-saitek.c
@@ -1,10 +1,17 @@
/*
- * HID driver for Saitek devices, currently only the PS1000 (USB gamepad).
+ * HID driver for Saitek devices.
+ *
+ * PS1000 (USB gamepad):
* Fixes the HID report descriptor by removing a non-existent axis and
* clearing the constant bit on the input reports for buttons and d-pad.
* (This module is based on "hid-ortek".)
- *
* Copyright (c) 2012 Andreas HĂĽbner
+ *
+ * R.A.T.7, M.M.O.7 (USB gaming mice):
+ * Fixes the mode button which cycles through three constantly pressed
+ * buttons. All three press events are mapped to one button and the
+ * missing release event is generated immediately.
+ *
*/
/*
@@ -21,12 +28,57 @@
#include "hid-ids.h"
+#define SAITEK_FIX_PS1000 0x0001
+#define SAITEK_RELEASE_MODE_RAT7 0x0002
+#define SAITEK_RELEASE_MODE_MMO7 0x0004
+
+struct saitek_sc {
+ unsigned long quirks;
+ int mode;
+};
+
+static int saitek_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ unsigned long quirks = id->driver_data;
+ struct saitek_sc *ssc;
+ int ret;
+
+ ssc = devm_kzalloc(&hdev->dev, sizeof(*ssc), GFP_KERNEL);
+ if (ssc == NULL) {
+ hid_err(hdev, "can't alloc saitek descriptor\n");
+ return -ENOMEM;
+ }
+
+ ssc->quirks = quirks;
+ ssc->mode = -1;
+
+ hid_set_drvdata(hdev, ssc);
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "parse failed\n");
+ return ret;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
static __u8 *saitek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
- if (*rsize == 137 && rdesc[20] == 0x09 && rdesc[21] == 0x33
- && rdesc[94] == 0x81 && rdesc[95] == 0x03
- && rdesc[110] == 0x81 && rdesc[111] == 0x03) {
+ struct saitek_sc *ssc = hid_get_drvdata(hdev);
+
+ if ((ssc->quirks & SAITEK_FIX_PS1000) && *rsize == 137 &&
+ rdesc[20] == 0x09 && rdesc[21] == 0x33 &&
+ rdesc[94] == 0x81 && rdesc[95] == 0x03 &&
+ rdesc[110] == 0x81 && rdesc[111] == 0x03) {
hid_info(hdev, "Fixing up Saitek PS1000 report descriptor\n");
@@ -42,8 +94,93 @@ static __u8 *saitek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
return rdesc;
}
+static int saitek_raw_event(struct hid_device *hdev,
+ struct hid_report *report, u8 *raw_data, int size)
+{
+ struct saitek_sc *ssc = hid_get_drvdata(hdev);
+
+ if (ssc->quirks & SAITEK_RELEASE_MODE_RAT7 && size == 7) {
+ /* R.A.T.7 uses bits 13, 14, 15 for the mode */
+ int mode = -1;
+ if (raw_data[1] & 0x01)
+ mode = 0;
+ else if (raw_data[1] & 0x02)
+ mode = 1;
+ else if (raw_data[1] & 0x04)
+ mode = 2;
+
+ /* clear mode bits */
+ raw_data[1] &= ~0x07;
+
+ if (mode != ssc->mode) {
+ hid_dbg(hdev, "entered mode %d\n", mode);
+ if (ssc->mode != -1) {
+ /* use bit 13 as the mode button */
+ raw_data[1] |= 0x04;
+ }
+ ssc->mode = mode;
+ }
+ } else if (ssc->quirks & SAITEK_RELEASE_MODE_MMO7 && size == 8) {
+
+ /* M.M.O.7 uses bits 8, 22, 23 for the mode */
+ int mode = -1;
+ if (raw_data[1] & 0x80)
+ mode = 0;
+ else if (raw_data[2] & 0x01)
+ mode = 1;
+ else if (raw_data[2] & 0x02)
+ mode = 2;
+
+ /* clear mode bits */
+ raw_data[1] &= ~0x80;
+ raw_data[2] &= ~0x03;
+
+ if (mode != ssc->mode) {
+ hid_dbg(hdev, "entered mode %d\n", mode);
+ if (ssc->mode != -1) {
+ /* use bit 8 as the mode button, bits 22
+ * and 23 do not represent buttons
+ * according to the HID report descriptor
+ */
+ raw_data[1] |= 0x80;
+ }
+ ssc->mode = mode;
+ }
+ }
+
+ return 0;
+}
+
+static int saitek_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct saitek_sc *ssc = hid_get_drvdata(hdev);
+ struct input_dev *input = field->hidinput->input;
+
+ if (usage->type == EV_KEY && value &&
+ (((ssc->quirks & SAITEK_RELEASE_MODE_RAT7) &&
+ usage->code - BTN_MOUSE == 10) ||
+ ((ssc->quirks & SAITEK_RELEASE_MODE_MMO7) &&
+ usage->code - BTN_MOUSE == 15))) {
+
+ input_report_key(input, usage->code, 1);
+
+ /* report missing release event */
+ input_report_key(input, usage->code, 0);
+
+ return 1;
+ }
+
+ return 0;
+}
+
static const struct hid_device_id saitek_devices[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000)},
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000),
+ .driver_data = SAITEK_FIX_PS1000 },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7),
+ .driver_data = SAITEK_RELEASE_MODE_RAT7 },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7),
+ .driver_data = SAITEK_RELEASE_MODE_MMO7 },
{ }
};
@@ -52,7 +189,10 @@ MODULE_DEVICE_TABLE(hid, saitek_devices);
static struct hid_driver saitek_driver = {
.name = "saitek",
.id_table = saitek_devices,
- .report_fixup = saitek_report_fixup
+ .probe = saitek_probe,
+ .report_fixup = saitek_report_fixup,
+ .raw_event = saitek_raw_event,
+ .event = saitek_event,
};
module_hid_driver(saitek_driver);
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index be14b5690e94..a8d5c8faf8cf 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -705,8 +705,17 @@ static const struct hid_device_id sensor_hub_devices[] = {
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_1,
USB_DEVICE_ID_INTEL_HID_SENSOR_1),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
+ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_MICROSOFT,
+ USB_DEVICE_ID_MS_SURFACE_PRO_2),
+ .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
+ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_MICROSOFT,
+ USB_DEVICE_ID_MS_TOUCH_COVER_2),
+ .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
+ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_MICROSOFT,
+ USB_DEVICE_ID_MS_TYPE_COVER_2),
+ .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_STM_0,
- USB_DEVICE_ID_STM_HID_SENSOR),
+ USB_DEVICE_ID_STM_HID_SENSOR_1),
.driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_TEXAS_INSTRUMENTS,
USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA),
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 908de2789219..2259eaa8b988 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -33,6 +33,7 @@
#include <linux/power_supply.h>
#include <linux/spinlock.h>
#include <linux/list.h>
+#include <linux/idr.h>
#include <linux/input/mt.h>
#include "hid-ids.h"
@@ -717,8 +718,39 @@ static enum power_supply_property sony_battery_props[] = {
POWER_SUPPLY_PROP_STATUS,
};
+struct sixaxis_led {
+ __u8 time_enabled; /* the total time the led is active (0xff means forever) */
+ __u8 duty_length; /* how long a cycle is in deciseconds (0 means "really fast") */
+ __u8 enabled;
+ __u8 duty_off; /* % of duty_length the led is off (0xff means 100%) */
+ __u8 duty_on; /* % of duty_length the led is on (0xff mean 100%) */
+} __packed;
+
+struct sixaxis_rumble {
+ __u8 padding;
+ __u8 right_duration; /* Right motor duration (0xff means forever) */
+ __u8 right_motor_on; /* Right (small) motor on/off, only supports values of 0 or 1 (off/on) */
+ __u8 left_duration; /* Left motor duration (0xff means forever) */
+ __u8 left_motor_force; /* left (large) motor, supports force values from 0 to 255 */
+} __packed;
+
+struct sixaxis_output_report {
+ __u8 report_id;
+ struct sixaxis_rumble rumble;
+ __u8 padding[4];
+ __u8 leds_bitmap; /* bitmap of enabled LEDs: LED_1 = 0x02, LED_2 = 0x04, ... */
+ struct sixaxis_led led[4]; /* LEDx at (4 - x) */
+ struct sixaxis_led _reserved; /* LED5, not actually soldered */
+} __packed;
+
+union sixaxis_output_report_01 {
+ struct sixaxis_output_report data;
+ __u8 buf[36];
+};
+
static spinlock_t sony_dev_list_lock;
static LIST_HEAD(sony_device_list);
+static DEFINE_IDA(sony_device_id_allocator);
struct sony_sc {
spinlock_t lock;
@@ -728,6 +760,7 @@ struct sony_sc {
unsigned long quirks;
struct work_struct state_worker;
struct power_supply battery;
+ int device_id;
#ifdef CONFIG_SONY_FF
__u8 left;
@@ -740,6 +773,8 @@ struct sony_sc {
__u8 battery_charging;
__u8 battery_capacity;
__u8 led_state[MAX_LEDS];
+ __u8 led_delay_on[MAX_LEDS];
+ __u8 led_delay_off[MAX_LEDS];
__u8 led_count;
};
@@ -1048,6 +1083,52 @@ static int dualshock4_set_operational_bt(struct hid_device *hdev)
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
}
+static void sixaxis_set_leds_from_id(int id, __u8 values[MAX_LEDS])
+{
+ static const __u8 sixaxis_leds[10][4] = {
+ { 0x01, 0x00, 0x00, 0x00 },
+ { 0x00, 0x01, 0x00, 0x00 },
+ { 0x00, 0x00, 0x01, 0x00 },
+ { 0x00, 0x00, 0x00, 0x01 },
+ { 0x01, 0x00, 0x00, 0x01 },
+ { 0x00, 0x01, 0x00, 0x01 },
+ { 0x00, 0x00, 0x01, 0x01 },
+ { 0x01, 0x00, 0x01, 0x01 },
+ { 0x00, 0x01, 0x01, 0x01 },
+ { 0x01, 0x01, 0x01, 0x01 }
+ };
+
+ BUG_ON(MAX_LEDS < ARRAY_SIZE(sixaxis_leds[0]));
+
+ if (id < 0)
+ return;
+
+ id %= 10;
+ memcpy(values, sixaxis_leds[id], sizeof(sixaxis_leds[id]));
+}
+
+static void dualshock4_set_leds_from_id(int id, __u8 values[MAX_LEDS])
+{
+ /* The first 4 color/index entries match what the PS4 assigns */
+ static const __u8 color_code[7][3] = {
+ /* Blue */ { 0x00, 0x00, 0x01 },
+ /* Red */ { 0x01, 0x00, 0x00 },
+ /* Green */ { 0x00, 0x01, 0x00 },
+ /* Pink */ { 0x02, 0x00, 0x01 },
+ /* Orange */ { 0x02, 0x01, 0x00 },
+ /* Teal */ { 0x00, 0x01, 0x01 },
+ /* White */ { 0x01, 0x01, 0x01 }
+ };
+
+ BUG_ON(MAX_LEDS < ARRAY_SIZE(color_code[0]));
+
+ if (id < 0)
+ return;
+
+ id %= 7;
+ memcpy(values, color_code[id], sizeof(color_code[id]));
+}
+
static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds)
{
struct list_head *report_list =
@@ -1066,19 +1147,18 @@ static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds)
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
}
-static void sony_set_leds(struct hid_device *hdev, const __u8 *leds, int count)
+static void sony_set_leds(struct sony_sc *sc, const __u8 *leds, int count)
{
- struct sony_sc *drv_data = hid_get_drvdata(hdev);
int n;
BUG_ON(count > MAX_LEDS);
- if (drv_data->quirks & BUZZ_CONTROLLER && count == 4) {
- buzz_set_leds(hdev, leds);
+ if (sc->quirks & BUZZ_CONTROLLER && count == 4) {
+ buzz_set_leds(sc->hdev, leds);
} else {
for (n = 0; n < count; n++)
- drv_data->led_state[n] = leds[n];
- schedule_work(&drv_data->state_worker);
+ sc->led_state[n] = leds[n];
+ schedule_work(&sc->state_worker);
}
}
@@ -1090,6 +1170,7 @@ static void sony_led_set_brightness(struct led_classdev *led,
struct sony_sc *drv_data;
int n;
+ int force_update;
drv_data = hid_get_drvdata(hdev);
if (!drv_data) {
@@ -1097,12 +1178,29 @@ static void sony_led_set_brightness(struct led_classdev *led,
return;
}
+ /*
+ * The Sixaxis on USB will override any LED settings sent to it
+ * and keep flashing all of the LEDs until the PS button is pressed.
+ * Updates, even if redundant, must be always be sent to the
+ * controller to avoid having to toggle the state of an LED just to
+ * stop the flashing later on.
+ */
+ force_update = !!(drv_data->quirks & SIXAXIS_CONTROLLER_USB);
+
for (n = 0; n < drv_data->led_count; n++) {
- if (led == drv_data->leds[n]) {
- if (value != drv_data->led_state[n]) {
- drv_data->led_state[n] = value;
- sony_set_leds(hdev, drv_data->led_state, drv_data->led_count);
- }
+ if (led == drv_data->leds[n] && (force_update ||
+ (value != drv_data->led_state[n] ||
+ drv_data->led_delay_on[n] ||
+ drv_data->led_delay_off[n]))) {
+
+ drv_data->led_state[n] = value;
+
+ /* Setting the brightness stops the blinking */
+ drv_data->led_delay_on[n] = 0;
+ drv_data->led_delay_off[n] = 0;
+
+ sony_set_leds(drv_data, drv_data->led_state,
+ drv_data->led_count);
break;
}
}
@@ -1130,63 +1228,112 @@ static enum led_brightness sony_led_get_brightness(struct led_classdev *led)
return LED_OFF;
}
-static void sony_leds_remove(struct hid_device *hdev)
+static int sony_led_blink_set(struct led_classdev *led, unsigned long *delay_on,
+ unsigned long *delay_off)
{
- struct sony_sc *drv_data;
- struct led_classdev *led;
+ struct device *dev = led->dev->parent;
+ struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct sony_sc *drv_data = hid_get_drvdata(hdev);
int n;
+ __u8 new_on, new_off;
- drv_data = hid_get_drvdata(hdev);
- BUG_ON(!(drv_data->quirks & SONY_LED_SUPPORT));
+ if (!drv_data) {
+ hid_err(hdev, "No device data\n");
+ return -EINVAL;
+ }
+
+ /* Max delay is 255 deciseconds or 2550 milliseconds */
+ if (*delay_on > 2550)
+ *delay_on = 2550;
+ if (*delay_off > 2550)
+ *delay_off = 2550;
+
+ /* Blink at 1 Hz if both values are zero */
+ if (!*delay_on && !*delay_off)
+ *delay_on = *delay_off = 500;
+
+ new_on = *delay_on / 10;
+ new_off = *delay_off / 10;
for (n = 0; n < drv_data->led_count; n++) {
- led = drv_data->leds[n];
- drv_data->leds[n] = NULL;
+ if (led == drv_data->leds[n])
+ break;
+ }
+
+ /* This LED is not registered on this device */
+ if (n >= drv_data->led_count)
+ return -EINVAL;
+
+ /* Don't schedule work if the values didn't change */
+ if (new_on != drv_data->led_delay_on[n] ||
+ new_off != drv_data->led_delay_off[n]) {
+ drv_data->led_delay_on[n] = new_on;
+ drv_data->led_delay_off[n] = new_off;
+ schedule_work(&drv_data->state_worker);
+ }
+
+ return 0;
+}
+
+static void sony_leds_remove(struct sony_sc *sc)
+{
+ struct led_classdev *led;
+ int n;
+
+ BUG_ON(!(sc->quirks & SONY_LED_SUPPORT));
+
+ for (n = 0; n < sc->led_count; n++) {
+ led = sc->leds[n];
+ sc->leds[n] = NULL;
if (!led)
continue;
led_classdev_unregister(led);
kfree(led);
}
- drv_data->led_count = 0;
+ sc->led_count = 0;
}
-static int sony_leds_init(struct hid_device *hdev)
+static int sony_leds_init(struct sony_sc *sc)
{
- struct sony_sc *drv_data;
+ struct hid_device *hdev = sc->hdev;
int n, ret = 0;
- int max_brightness;
- int use_colors;
+ int use_ds4_names;
struct led_classdev *led;
size_t name_sz;
char *name;
size_t name_len;
const char *name_fmt;
- static const char * const color_str[] = { "red", "green", "blue" };
- static const __u8 initial_values[MAX_LEDS] = { 0x00, 0x00, 0x00, 0x00 };
+ static const char * const ds4_name_str[] = { "red", "green", "blue",
+ "global" };
+ __u8 initial_values[MAX_LEDS] = { 0 };
+ __u8 max_brightness[MAX_LEDS] = { 1 };
+ __u8 use_hw_blink[MAX_LEDS] = { 0 };
- drv_data = hid_get_drvdata(hdev);
- BUG_ON(!(drv_data->quirks & SONY_LED_SUPPORT));
+ BUG_ON(!(sc->quirks & SONY_LED_SUPPORT));
- if (drv_data->quirks & BUZZ_CONTROLLER) {
- drv_data->led_count = 4;
- max_brightness = 1;
- use_colors = 0;
+ if (sc->quirks & BUZZ_CONTROLLER) {
+ sc->led_count = 4;
+ use_ds4_names = 0;
name_len = strlen("::buzz#");
name_fmt = "%s::buzz%d";
/* Validate expected report characteristics. */
if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7))
return -ENODEV;
- } else if (drv_data->quirks & DUALSHOCK4_CONTROLLER) {
- drv_data->led_count = 3;
- max_brightness = 255;
- use_colors = 1;
+ } else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
+ dualshock4_set_leds_from_id(sc->device_id, initial_values);
+ initial_values[3] = 1;
+ sc->led_count = 4;
+ memset(max_brightness, 255, 3);
+ use_hw_blink[3] = 1;
+ use_ds4_names = 1;
name_len = 0;
name_fmt = "%s:%s";
} else {
- drv_data->led_count = 4;
- max_brightness = 1;
- use_colors = 0;
+ sixaxis_set_leds_from_id(sc->device_id, initial_values);
+ sc->led_count = 4;
+ memset(use_hw_blink, 1, 4);
+ use_ds4_names = 0;
name_len = strlen("::sony#");
name_fmt = "%s::sony%d";
}
@@ -1196,14 +1343,14 @@ static int sony_leds_init(struct hid_device *hdev)
* only relevant if the driver is loaded after somebody actively set the
* LEDs to on
*/
- sony_set_leds(hdev, initial_values, drv_data->led_count);
+ sony_set_leds(sc, initial_values, sc->led_count);
name_sz = strlen(dev_name(&hdev->dev)) + name_len + 1;
- for (n = 0; n < drv_data->led_count; n++) {
+ for (n = 0; n < sc->led_count; n++) {
- if (use_colors)
- name_sz = strlen(dev_name(&hdev->dev)) + strlen(color_str[n]) + 2;
+ if (use_ds4_names)
+ name_sz = strlen(dev_name(&hdev->dev)) + strlen(ds4_name_str[n]) + 2;
led = kzalloc(sizeof(struct led_classdev) + name_sz, GFP_KERNEL);
if (!led) {
@@ -1213,30 +1360,35 @@ static int sony_leds_init(struct hid_device *hdev)
}
name = (void *)(&led[1]);
- if (use_colors)
- snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), color_str[n]);
+ if (use_ds4_names)
+ snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev),
+ ds4_name_str[n]);
else
snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1);
led->name = name;
- led->brightness = 0;
- led->max_brightness = max_brightness;
+ led->brightness = initial_values[n];
+ led->max_brightness = max_brightness[n];
led->brightness_get = sony_led_get_brightness;
led->brightness_set = sony_led_set_brightness;
+ if (use_hw_blink[n])
+ led->blink_set = sony_led_blink_set;
+
+ sc->leds[n] = led;
+
ret = led_classdev_register(&hdev->dev, led);
if (ret) {
hid_err(hdev, "Failed to register LED %d\n", n);
+ sc->leds[n] = NULL;
kfree(led);
goto error_leds;
}
-
- drv_data->leds[n] = led;
}
return ret;
error_leds:
- sony_leds_remove(hdev);
+ sony_leds_remove(sc);
return ret;
}
@@ -1244,29 +1396,52 @@ error_leds:
static void sixaxis_state_worker(struct work_struct *work)
{
struct sony_sc *sc = container_of(work, struct sony_sc, state_worker);
- unsigned char buf[] = {
- 0x01,
- 0x00, 0xff, 0x00, 0xff, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00,
- 0xff, 0x27, 0x10, 0x00, 0x32,
- 0xff, 0x27, 0x10, 0x00, 0x32,
- 0xff, 0x27, 0x10, 0x00, 0x32,
- 0xff, 0x27, 0x10, 0x00, 0x32,
- 0x00, 0x00, 0x00, 0x00, 0x00
+ int n;
+ union sixaxis_output_report_01 report = {
+ .buf = {
+ 0x01,
+ 0x00, 0xff, 0x00, 0xff, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0x27, 0x10, 0x00, 0x32,
+ 0xff, 0x27, 0x10, 0x00, 0x32,
+ 0xff, 0x27, 0x10, 0x00, 0x32,
+ 0xff, 0x27, 0x10, 0x00, 0x32,
+ 0x00, 0x00, 0x00, 0x00, 0x00
+ }
};
#ifdef CONFIG_SONY_FF
- buf[3] = sc->right ? 1 : 0;
- buf[5] = sc->left;
+ report.data.rumble.right_motor_on = sc->right ? 1 : 0;
+ report.data.rumble.left_motor_force = sc->left;
#endif
- buf[10] |= sc->led_state[0] << 1;
- buf[10] |= sc->led_state[1] << 2;
- buf[10] |= sc->led_state[2] << 3;
- buf[10] |= sc->led_state[3] << 4;
+ report.data.leds_bitmap |= sc->led_state[0] << 1;
+ report.data.leds_bitmap |= sc->led_state[1] << 2;
+ report.data.leds_bitmap |= sc->led_state[2] << 3;
+ report.data.leds_bitmap |= sc->led_state[3] << 4;
+
+ /* Set flag for all leds off, required for 3rd party INTEC controller */
+ if ((report.data.leds_bitmap & 0x1E) == 0)
+ report.data.leds_bitmap |= 0x20;
- hid_hw_raw_request(sc->hdev, 0x01, buf, sizeof(buf), HID_OUTPUT_REPORT,
- HID_REQ_SET_REPORT);
+ /*
+ * The LEDs in the report are indexed in reverse order to their
+ * corresponding light on the controller.
+ * Index 0 = LED 4, index 1 = LED 3, etc...
+ *
+ * In the case of both delay values being zero (blinking disabled) the
+ * default report values should be used or the controller LED will be
+ * always off.
+ */
+ for (n = 0; n < 4; n++) {
+ if (sc->led_delay_on[n] || sc->led_delay_off[n]) {
+ report.data.led[3 - n].duty_off = sc->led_delay_off[n];
+ report.data.led[3 - n].duty_on = sc->led_delay_on[n];
+ }
+ }
+
+ hid_hw_raw_request(sc->hdev, report.data.report_id, report.buf,
+ sizeof(report), HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
}
static void dualshock4_state_worker(struct work_struct *work)
@@ -1279,7 +1454,7 @@ static void dualshock4_state_worker(struct work_struct *work)
if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) {
buf[0] = 0x05;
- buf[1] = 0x03;
+ buf[1] = 0xFF;
offset = 4;
} else {
buf[0] = 0x11;
@@ -1295,9 +1470,18 @@ static void dualshock4_state_worker(struct work_struct *work)
offset += 2;
#endif
- buf[offset++] = sc->led_state[0];
- buf[offset++] = sc->led_state[1];
- buf[offset++] = sc->led_state[2];
+ /* LED 3 is the global control */
+ if (sc->led_state[3]) {
+ buf[offset++] = sc->led_state[0];
+ buf[offset++] = sc->led_state[1];
+ buf[offset++] = sc->led_state[2];
+ } else {
+ offset += 3;
+ }
+
+ /* If both delay values are zero the DualShock 4 disables blinking. */
+ buf[offset++] = sc->led_delay_on[3];
+ buf[offset++] = sc->led_delay_off[3];
if (sc->quirks & DUALSHOCK4_CONTROLLER_USB)
hid_hw_output_report(hdev, buf, 32);
@@ -1323,9 +1507,9 @@ static int sony_play_effect(struct input_dev *dev, void *data,
return 0;
}
-static int sony_init_ff(struct hid_device *hdev)
+static int sony_init_ff(struct sony_sc *sc)
{
- struct hid_input *hidinput = list_entry(hdev->inputs.next,
+ struct hid_input *hidinput = list_entry(sc->hdev->inputs.next,
struct hid_input, list);
struct input_dev *input_dev = hidinput->input;
@@ -1334,7 +1518,7 @@ static int sony_init_ff(struct hid_device *hdev)
}
#else
-static int sony_init_ff(struct hid_device *hdev)
+static int sony_init_ff(struct sony_sc *sc)
{
return 0;
}
@@ -1384,8 +1568,6 @@ static int sony_battery_get_property(struct power_supply *psy,
static int sony_battery_probe(struct sony_sc *sc)
{
- static atomic_t power_id_seq = ATOMIC_INIT(0);
- unsigned long power_id;
struct hid_device *hdev = sc->hdev;
int ret;
@@ -1395,15 +1577,13 @@ static int sony_battery_probe(struct sony_sc *sc)
*/
sc->battery_capacity = 100;
- power_id = (unsigned long)atomic_inc_return(&power_id_seq);
-
sc->battery.properties = sony_battery_props;
sc->battery.num_properties = ARRAY_SIZE(sony_battery_props);
sc->battery.get_property = sony_battery_get_property;
sc->battery.type = POWER_SUPPLY_TYPE_BATTERY;
sc->battery.use_for_apm = 0;
- sc->battery.name = kasprintf(GFP_KERNEL, "sony_controller_battery_%lu",
- power_id);
+ sc->battery.name = kasprintf(GFP_KERNEL, "sony_controller_battery_%pMR",
+ sc->mac_address);
if (!sc->battery.name)
return -ENOMEM;
@@ -1578,6 +1758,52 @@ static int sony_check_add(struct sony_sc *sc)
return sony_check_add_dev_list(sc);
}
+static int sony_set_device_id(struct sony_sc *sc)
+{
+ int ret;
+
+ /*
+ * Only DualShock 4 or Sixaxis controllers get an id.
+ * All others are set to -1.
+ */
+ if ((sc->quirks & SIXAXIS_CONTROLLER) ||
+ (sc->quirks & DUALSHOCK4_CONTROLLER)) {
+ ret = ida_simple_get(&sony_device_id_allocator, 0, 0,
+ GFP_KERNEL);
+ if (ret < 0) {
+ sc->device_id = -1;
+ return ret;
+ }
+ sc->device_id = ret;
+ } else {
+ sc->device_id = -1;
+ }
+
+ return 0;
+}
+
+static void sony_release_device_id(struct sony_sc *sc)
+{
+ if (sc->device_id >= 0) {
+ ida_simple_remove(&sony_device_id_allocator, sc->device_id);
+ sc->device_id = -1;
+ }
+}
+
+static inline void sony_init_work(struct sony_sc *sc,
+ void (*worker)(struct work_struct *))
+{
+ if (!sc->worker_initialized)
+ INIT_WORK(&sc->state_worker, worker);
+
+ sc->worker_initialized = 1;
+}
+
+static inline void sony_cancel_work_sync(struct sony_sc *sc)
+{
+ if (sc->worker_initialized)
+ cancel_work_sync(&sc->state_worker);
+}
static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
@@ -1615,6 +1841,12 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
}
+ ret = sony_set_device_id(sc);
+ if (ret < 0) {
+ hid_err(hdev, "failed to allocate the device id\n");
+ goto err_stop;
+ }
+
if (sc->quirks & SIXAXIS_CONTROLLER_USB) {
/*
* The Sony Sixaxis does not handle HID Output Reports on the
@@ -1629,8 +1861,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID;
ret = sixaxis_set_operational_usb(hdev);
- sc->worker_initialized = 1;
- INIT_WORK(&sc->state_worker, sixaxis_state_worker);
+ sony_init_work(sc, sixaxis_state_worker);
} else if (sc->quirks & SIXAXIS_CONTROLLER_BT) {
/*
* The Sixaxis wants output reports sent on the ctrl endpoint
@@ -1638,8 +1869,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
*/
hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP;
ret = sixaxis_set_operational_bt(hdev);
- sc->worker_initialized = 1;
- INIT_WORK(&sc->state_worker, sixaxis_state_worker);
+ sony_init_work(sc, sixaxis_state_worker);
} else if (sc->quirks & DUALSHOCK4_CONTROLLER) {
if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) {
/*
@@ -1661,8 +1891,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret < 0)
goto err_stop;
- sc->worker_initialized = 1;
- INIT_WORK(&sc->state_worker, dualshock4_state_worker);
+ sony_init_work(sc, dualshock4_state_worker);
} else {
ret = 0;
}
@@ -1675,7 +1904,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto err_stop;
if (sc->quirks & SONY_LED_SUPPORT) {
- ret = sony_leds_init(hdev);
+ ret = sony_leds_init(sc);
if (ret < 0)
goto err_stop;
}
@@ -1694,7 +1923,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
if (sc->quirks & SONY_FF_SUPPORT) {
- ret = sony_init_ff(hdev);
+ ret = sony_init_ff(sc);
if (ret < 0)
goto err_close;
}
@@ -1704,12 +1933,12 @@ err_close:
hid_hw_close(hdev);
err_stop:
if (sc->quirks & SONY_LED_SUPPORT)
- sony_leds_remove(hdev);
+ sony_leds_remove(sc);
if (sc->quirks & SONY_BATTERY_SUPPORT)
sony_battery_remove(sc);
- if (sc->worker_initialized)
- cancel_work_sync(&sc->state_worker);
+ sony_cancel_work_sync(sc);
sony_remove_dev_list(sc);
+ sony_release_device_id(sc);
hid_hw_stop(hdev);
return ret;
}
@@ -1719,18 +1948,19 @@ static void sony_remove(struct hid_device *hdev)
struct sony_sc *sc = hid_get_drvdata(hdev);
if (sc->quirks & SONY_LED_SUPPORT)
- sony_leds_remove(hdev);
+ sony_leds_remove(sc);
if (sc->quirks & SONY_BATTERY_SUPPORT) {
hid_hw_close(hdev);
sony_battery_remove(sc);
}
- if (sc->worker_initialized)
- cancel_work_sync(&sc->state_worker);
+ sony_cancel_work_sync(sc);
sony_remove_dev_list(sc);
+ sony_release_device_id(sc);
+
hid_hw_stop(hdev);
}
@@ -1775,6 +2005,22 @@ static struct hid_driver sony_driver = {
.report_fixup = sony_report_fixup,
.raw_event = sony_raw_event
};
-module_hid_driver(sony_driver);
+
+static int __init sony_init(void)
+{
+ dbg_hid("Sony:%s\n", __func__);
+
+ return hid_register_driver(&sony_driver);
+}
+
+static void __exit sony_exit(void)
+{
+ dbg_hid("Sony:%s\n", __func__);
+
+ ida_destroy(&sony_device_id_allocator);
+ hid_unregister_driver(&sony_driver);
+}
+module_init(sony_init);
+module_exit(sony_exit);
MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-thingm.c b/drivers/hid/hid-thingm.c
index a97c78845f7b..134be89b15ea 100644
--- a/drivers/hid/hid-thingm.c
+++ b/drivers/hid/hid-thingm.c
@@ -1,7 +1,7 @@
/*
* ThingM blink(1) USB RGB LED driver
*
- * Copyright 2013 Savoir-faire Linux Inc.
+ * Copyright 2013-2014 Savoir-faire Linux Inc.
* Vivien Didelot <vivien.didelot@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or
@@ -10,244 +10,285 @@
*/
#include <linux/hid.h>
+#include <linux/hidraw.h>
#include <linux/leds.h>
#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
#include "hid-ids.h"
-#define BLINK1_CMD_SIZE 9
+#define REPORT_ID 1
+#define REPORT_SIZE 9
-#define blink1_rgb_to_r(rgb) ((rgb & 0xFF0000) >> 16)
-#define blink1_rgb_to_g(rgb) ((rgb & 0x00FF00) >> 8)
-#define blink1_rgb_to_b(rgb) ((rgb & 0x0000FF) >> 0)
+/* Firmware major number of supported devices */
+#define THINGM_MAJOR_MK1 '1'
+#define THINGM_MAJOR_MK2 '2'
-/**
- * struct blink1_data - blink(1) device specific data
- * @hdev: HID device.
- * @led_cdev: LED class instance.
- * @rgb: 8-bit per channel RGB notation.
- * @fade: fade time in hundredths of a second.
- * @brightness: brightness coefficient.
- * @play: play/pause in-memory patterns.
- */
-struct blink1_data {
+struct thingm_fwinfo {
+ char major;
+ unsigned numrgb;
+ unsigned first;
+};
+
+static const struct thingm_fwinfo thingm_fwinfo[] = {
+ {
+ .major = THINGM_MAJOR_MK1,
+ .numrgb = 1,
+ .first = 0,
+ }, {
+ .major = THINGM_MAJOR_MK2,
+ .numrgb = 2,
+ .first = 1,
+ }
+};
+
+/* A red, green or blue channel, part of an RGB chip */
+struct thingm_led {
+ struct thingm_rgb *rgb;
+ struct led_classdev ldev;
+ char name[32];
+};
+
+/* Basically a WS2812 5050 RGB LED chip */
+struct thingm_rgb {
+ struct thingm_device *tdev;
+ struct thingm_led red;
+ struct thingm_led green;
+ struct thingm_led blue;
+ struct work_struct work;
+ u8 num;
+};
+
+struct thingm_device {
struct hid_device *hdev;
- struct led_classdev led_cdev;
- u32 rgb;
- u16 fade;
- u8 brightness;
- bool play;
+ struct {
+ char major;
+ char minor;
+ } version;
+ const struct thingm_fwinfo *fwinfo;
+ struct mutex lock;
+ struct thingm_rgb *rgb;
};
-static int blink1_send_command(struct blink1_data *data,
- u8 buf[BLINK1_CMD_SIZE])
+static int thingm_send(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
{
int ret;
- hid_dbg(data->hdev, "command: %d%c%.2x%.2x%.2x%.2x%.2x%.2x%.2x\n",
+ hid_dbg(tdev->hdev, "-> %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
buf[0], buf[1], buf[2], buf[3], buf[4],
buf[5], buf[6], buf[7], buf[8]);
- ret = hid_hw_raw_request(data->hdev, buf[0], buf, BLINK1_CMD_SIZE,
- HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+ ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
+ HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
return ret < 0 ? ret : 0;
}
-static int blink1_update_color(struct blink1_data *data)
+static int thingm_recv(struct thingm_device *tdev, u8 buf[REPORT_SIZE])
{
- u8 buf[BLINK1_CMD_SIZE] = { 1, 'n', 0, 0, 0, 0, 0, 0, 0 };
-
- if (data->brightness) {
- unsigned int coef = DIV_ROUND_CLOSEST(255, data->brightness);
+ int ret;
- buf[2] = DIV_ROUND_CLOSEST(blink1_rgb_to_r(data->rgb), coef);
- buf[3] = DIV_ROUND_CLOSEST(blink1_rgb_to_g(data->rgb), coef);
- buf[4] = DIV_ROUND_CLOSEST(blink1_rgb_to_b(data->rgb), coef);
- }
+ ret = hid_hw_raw_request(tdev->hdev, buf[0], buf, REPORT_SIZE,
+ HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+ if (ret < 0)
+ return ret;
- if (data->fade) {
- buf[1] = 'c';
- buf[5] = (data->fade & 0xFF00) >> 8;
- buf[6] = (data->fade & 0x00FF);
- }
+ hid_dbg(tdev->hdev, "<- %d %c %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx\n",
+ buf[0], buf[1], buf[2], buf[3], buf[4],
+ buf[5], buf[6], buf[7], buf[8]);
- return blink1_send_command(data, buf);
+ return 0;
}
-static void blink1_led_set(struct led_classdev *led_cdev,
- enum led_brightness brightness)
+static int thingm_version(struct thingm_device *tdev)
{
- struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent);
+ u8 buf[REPORT_SIZE] = { REPORT_ID, 'v', 0, 0, 0, 0, 0, 0, 0 };
+ int err;
- data->brightness = brightness;
- if (blink1_update_color(data))
- hid_err(data->hdev, "failed to update color\n");
-}
+ err = thingm_send(tdev, buf);
+ if (err)
+ return err;
-static enum led_brightness blink1_led_get(struct led_classdev *led_cdev)
-{
- struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent);
+ err = thingm_recv(tdev, buf);
+ if (err)
+ return err;
- return data->brightness;
+ tdev->version.major = buf[3];
+ tdev->version.minor = buf[4];
+
+ return 0;
}
-static ssize_t blink1_show_rgb(struct device *dev,
- struct device_attribute *attr, char *buf)
+static int thingm_write_color(struct thingm_rgb *rgb)
{
- struct blink1_data *data = dev_get_drvdata(dev->parent);
+ u8 buf[REPORT_SIZE] = { REPORT_ID, 'c', 0, 0, 0, 0, 0, rgb->num, 0 };
- return sprintf(buf, "%.6X\n", data->rgb);
+ buf[2] = rgb->red.ldev.brightness;
+ buf[3] = rgb->green.ldev.brightness;
+ buf[4] = rgb->blue.ldev.brightness;
+
+ return thingm_send(rgb->tdev, buf);
}
-static ssize_t blink1_store_rgb(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static void thingm_work(struct work_struct *work)
{
- struct blink1_data *data = dev_get_drvdata(dev->parent);
- long unsigned int rgb;
- int ret;
+ struct thingm_rgb *rgb = container_of(work, struct thingm_rgb, work);
- ret = kstrtoul(buf, 16, &rgb);
- if (ret)
- return ret;
-
- /* RGB triplet notation is 24-bit hexadecimal */
- if (rgb > 0xFFFFFF)
- return -EINVAL;
+ mutex_lock(&rgb->tdev->lock);
- data->rgb = rgb;
- ret = blink1_update_color(data);
+ if (thingm_write_color(rgb))
+ hid_err(rgb->tdev->hdev, "failed to write color\n");
- return ret ? ret : count;
+ mutex_unlock(&rgb->tdev->lock);
}
-static DEVICE_ATTR(rgb, S_IRUGO | S_IWUSR, blink1_show_rgb, blink1_store_rgb);
-
-static ssize_t blink1_show_fade(struct device *dev,
- struct device_attribute *attr, char *buf)
+static void thingm_led_set(struct led_classdev *ldev,
+ enum led_brightness brightness)
{
- struct blink1_data *data = dev_get_drvdata(dev->parent);
+ struct thingm_led *led = container_of(ldev, struct thingm_led, ldev);
- return sprintf(buf, "%d\n", data->fade * 10);
+ /* the ledclass has already stored the brightness value */
+ schedule_work(&led->rgb->work);
}
-static ssize_t blink1_store_fade(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static int thingm_init_rgb(struct thingm_rgb *rgb)
{
- struct blink1_data *data = dev_get_drvdata(dev->parent);
- long unsigned int fade;
- int ret;
+ const int minor = ((struct hidraw *) rgb->tdev->hdev->hidraw)->minor;
+ int err;
+
+ /* Register the red diode */
+ snprintf(rgb->red.name, sizeof(rgb->red.name),
+ "thingm%d:red:led%d", minor, rgb->num);
+ rgb->red.ldev.name = rgb->red.name;
+ rgb->red.ldev.max_brightness = 255;
+ rgb->red.ldev.brightness_set = thingm_led_set;
+ rgb->red.rgb = rgb;
+
+ err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->red.ldev);
+ if (err)
+ return err;
+
+ /* Register the green diode */
+ snprintf(rgb->green.name, sizeof(rgb->green.name),
+ "thingm%d:green:led%d", minor, rgb->num);
+ rgb->green.ldev.name = rgb->green.name;
+ rgb->green.ldev.max_brightness = 255;
+ rgb->green.ldev.brightness_set = thingm_led_set;
+ rgb->green.rgb = rgb;
+
+ err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->green.ldev);
+ if (err)
+ goto unregister_red;
+
+ /* Register the blue diode */
+ snprintf(rgb->blue.name, sizeof(rgb->blue.name),
+ "thingm%d:blue:led%d", minor, rgb->num);
+ rgb->blue.ldev.name = rgb->blue.name;
+ rgb->blue.ldev.max_brightness = 255;
+ rgb->blue.ldev.brightness_set = thingm_led_set;
+ rgb->blue.rgb = rgb;
+
+ err = led_classdev_register(&rgb->tdev->hdev->dev, &rgb->blue.ldev);
+ if (err)
+ goto unregister_green;
+
+ INIT_WORK(&rgb->work, thingm_work);
- ret = kstrtoul(buf, 10, &fade);
- if (ret)
- return ret;
+ return 0;
- /* blink(1) accepts 16-bit fade time, number of 10ms ticks */
- fade = DIV_ROUND_CLOSEST(fade, 10);
- if (fade > 65535)
- return -EINVAL;
+unregister_green:
+ led_classdev_unregister(&rgb->green.ldev);
- data->fade = fade;
+unregister_red:
+ led_classdev_unregister(&rgb->red.ldev);
- return count;
+ return err;
}
-static DEVICE_ATTR(fade, S_IRUGO | S_IWUSR,
- blink1_show_fade, blink1_store_fade);
-
-static ssize_t blink1_show_play(struct device *dev,
- struct device_attribute *attr, char *buf)
+static void thingm_remove_rgb(struct thingm_rgb *rgb)
{
- struct blink1_data *data = dev_get_drvdata(dev->parent);
-
- return sprintf(buf, "%d\n", data->play);
+ flush_work(&rgb->work);
+ led_classdev_unregister(&rgb->red.ldev);
+ led_classdev_unregister(&rgb->green.ldev);
+ led_classdev_unregister(&rgb->blue.ldev);
}
-static ssize_t blink1_store_play(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
+static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
- struct blink1_data *data = dev_get_drvdata(dev->parent);
- u8 cmd[BLINK1_CMD_SIZE] = { 1, 'p', 0, 0, 0, 0, 0, 0, 0 };
- long unsigned int play;
- int ret;
+ struct thingm_device *tdev;
+ int i, err;
- ret = kstrtoul(buf, 10, &play);
- if (ret)
- return ret;
+ tdev = devm_kzalloc(&hdev->dev, sizeof(struct thingm_device),
+ GFP_KERNEL);
+ if (!tdev)
+ return -ENOMEM;
- data->play = !!play;
- cmd[2] = data->play;
- ret = blink1_send_command(data, cmd);
+ tdev->hdev = hdev;
+ hid_set_drvdata(hdev, tdev);
- return ret ? ret : count;
-}
-
-static DEVICE_ATTR(play, S_IRUGO | S_IWUSR,
- blink1_show_play, blink1_store_play);
+ err = hid_parse(hdev);
+ if (err)
+ goto error;
-static const struct attribute_group blink1_sysfs_group = {
- .attrs = (struct attribute *[]) {
- &dev_attr_rgb.attr,
- &dev_attr_fade.attr,
- &dev_attr_play.attr,
- NULL
- },
-};
+ err = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
+ if (err)
+ goto error;
-static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
-{
- struct blink1_data *data;
- struct led_classdev *led;
- char led_name[13];
- int ret;
+ mutex_init(&tdev->lock);
- data = devm_kzalloc(&hdev->dev, sizeof(struct blink1_data), GFP_KERNEL);
- if (!data)
- return -ENOMEM;
+ err = thingm_version(tdev);
+ if (err)
+ goto stop;
- hid_set_drvdata(hdev, data);
- data->hdev = hdev;
- data->rgb = 0xFFFFFF; /* set a default white color */
+ hid_dbg(hdev, "firmware version: %c.%c\n",
+ tdev->version.major, tdev->version.minor);
- ret = hid_parse(hdev);
- if (ret)
- goto error;
+ for (i = 0; i < ARRAY_SIZE(thingm_fwinfo) && !tdev->fwinfo; ++i)
+ if (thingm_fwinfo[i].major == tdev->version.major)
+ tdev->fwinfo = &thingm_fwinfo[i];
- ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
- if (ret)
- goto error;
+ if (!tdev->fwinfo) {
+ hid_err(hdev, "unsupported firmware %c\n", tdev->version.major);
+ goto stop;
+ }
- /* blink(1) serial numbers range is 0x1A001000 to 0x1A002FFF */
- led = &data->led_cdev;
- snprintf(led_name, sizeof(led_name), "blink1::%s", hdev->uniq + 4);
- led->name = led_name;
- led->brightness_set = blink1_led_set;
- led->brightness_get = blink1_led_get;
- ret = led_classdev_register(&hdev->dev, led);
- if (ret)
+ tdev->rgb = devm_kzalloc(&hdev->dev,
+ sizeof(struct thingm_rgb) * tdev->fwinfo->numrgb,
+ GFP_KERNEL);
+ if (!tdev->rgb) {
+ err = -ENOMEM;
goto stop;
+ }
- ret = sysfs_create_group(&led->dev->kobj, &blink1_sysfs_group);
- if (ret)
- goto remove_led;
+ for (i = 0; i < tdev->fwinfo->numrgb; ++i) {
+ struct thingm_rgb *rgb = tdev->rgb + i;
+
+ rgb->tdev = tdev;
+ rgb->num = tdev->fwinfo->first + i;
+ err = thingm_init_rgb(rgb);
+ if (err) {
+ while (--i >= 0)
+ thingm_remove_rgb(tdev->rgb + i);
+ goto stop;
+ }
+ }
return 0;
-
-remove_led:
- led_classdev_unregister(led);
stop:
hid_hw_stop(hdev);
error:
- return ret;
+ return err;
}
static void thingm_remove(struct hid_device *hdev)
{
- struct blink1_data *data = hid_get_drvdata(hdev);
- struct led_classdev *led = &data->led_cdev;
+ struct thingm_device *tdev = hid_get_drvdata(hdev);
+ int i;
+
+ for (i = 0; i < tdev->fwinfo->numrgb; ++i)
+ thingm_remove_rgb(tdev->rgb + i);
- sysfs_remove_group(&led->dev->kobj, &blink1_sysfs_group);
- led_classdev_unregister(led);
hid_hw_stop(hdev);
}
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index b50860db92f1..21aafc8f48c8 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -807,34 +807,18 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
unsigned int dsize;
int ret;
- /* Fetch the length of HID description, retrieve the 4 first bytes:
- * bytes 0-1 -> length
- * bytes 2-3 -> bcdVersion (has to be 1.00) */
- ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer, 4);
-
- i2c_hid_dbg(ihid, "%s, ihid->hdesc_buffer: %4ph\n", __func__,
- ihid->hdesc_buffer);
-
+ /* i2c hid fetch using a fixed descriptor size (30 bytes) */
+ i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
+ ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer,
+ sizeof(struct i2c_hid_desc));
if (ret) {
- dev_err(&client->dev,
- "unable to fetch the size of HID descriptor (ret=%d)\n",
- ret);
- return -ENODEV;
- }
-
- dsize = le16_to_cpu(hdesc->wHIDDescLength);
- /*
- * the size of the HID descriptor should at least contain
- * its size and the bcdVersion (4 bytes), and should not be greater
- * than sizeof(struct i2c_hid_desc) as we directly fill this struct
- * through i2c_hid_command.
- */
- if (dsize < 4 || dsize > sizeof(struct i2c_hid_desc)) {
- dev_err(&client->dev, "weird size of HID descriptor (%u)\n",
- dsize);
+ dev_err(&client->dev, "hid_descr_cmd failed\n");
return -ENODEV;
}
+ /* Validate the length of HID descriptor, the 4 first bytes:
+ * bytes 0-1 -> length
+ * bytes 2-3 -> bcdVersion (has to be 1.00) */
/* check bcdVersion == 1.0 */
if (le16_to_cpu(hdesc->bcdVersion) != 0x0100) {
dev_err(&client->dev,
@@ -843,17 +827,14 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
return -ENODEV;
}
- i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
-
- ret = i2c_hid_command(client, &hid_descr_cmd, ihid->hdesc_buffer,
- dsize);
- if (ret) {
- dev_err(&client->dev, "hid_descr_cmd Fail\n");
+ /* Descriptor length should be 30 bytes as per the specification */
+ dsize = le16_to_cpu(hdesc->wHIDDescLength);
+ if (dsize != sizeof(struct i2c_hid_desc)) {
+ dev_err(&client->dev, "weird size of HID descriptor (%u)\n",
+ dsize);
return -ENODEV;
}
-
i2c_hid_dbg(ihid, "HID Descriptor: %*ph\n", dsize, ihid->hdesc_buffer);
-
return 0;
}
diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c
index 0d078c32db4f..0cb92e347258 100644
--- a/drivers/hid/uhid.c
+++ b/drivers/hid/uhid.c
@@ -441,12 +441,11 @@ static int uhid_dev_create2(struct uhid_device *uhid,
if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE)
return -EINVAL;
- uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL);
+ uhid->rd_data = kmemdup(ev->u.create2.rd_data, uhid->rd_size,
+ GFP_KERNEL);
if (!uhid->rd_data)
return -ENOMEM;
- memcpy(uhid->rd_data, ev->u.create2.rd_data, uhid->rd_size);
-
hid = hid_allocate_device();
if (IS_ERR(hid)) {
ret = PTR_ERR(hid);
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 8e4ddb369883..59badc10a08c 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -115,6 +115,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_DUOSENSE, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_SEMICO, USB_DEVICE_ID_SEMICO_USB_KEYKOARD, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS1, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_LTS2, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_HD, HID_QUIRK_NO_INIT_REPORTS },
diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c
index 63b3d4eb0ef7..4044ff287663 100644
--- a/drivers/irqchip/irq-mxs.c
+++ b/drivers/irqchip/irq-mxs.c
@@ -96,7 +96,7 @@ static struct irq_domain_ops icoll_irq_domain_ops = {
.xlate = irq_domain_xlate_onecell,
};
-static void __init icoll_of_init(struct device_node *np,
+static int __init icoll_of_init(struct device_node *np,
struct device_node *interrupt_parent)
{
icoll_base = of_iomap(np, 0);
@@ -110,6 +110,6 @@ static void __init icoll_of_init(struct device_node *np,
icoll_domain = irq_domain_add_linear(np, ICOLL_NUM_IRQS,
&icoll_irq_domain_ops, NULL);
- WARN_ON(!icoll_domain);
+ return icoll_domain ? 0 : -ENODEV;
}
IRQCHIP_DECLARE(mxs, "fsl,icoll", icoll_of_init);
diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c
index bbcc944ed94f..78a6accd205f 100644
--- a/drivers/irqchip/irq-s3c24xx.c
+++ b/drivers/irqchip/irq-s3c24xx.c
@@ -1323,8 +1323,7 @@ static struct s3c24xx_irq_of_ctrl s3c2410_ctrl[] = {
};
int __init s3c2410_init_intc_of(struct device_node *np,
- struct device_node *interrupt_parent,
- struct s3c24xx_irq_of_ctrl *ctrl, int num_ctrl)
+ struct device_node *interrupt_parent)
{
return s3c_init_intc_of(np, interrupt_parent,
s3c2410_ctrl, ARRAY_SIZE(s3c2410_ctrl));
@@ -1346,8 +1345,7 @@ static struct s3c24xx_irq_of_ctrl s3c2416_ctrl[] = {
};
int __init s3c2416_init_intc_of(struct device_node *np,
- struct device_node *interrupt_parent,
- struct s3c24xx_irq_of_ctrl *ctrl, int num_ctrl)
+ struct device_node *interrupt_parent)
{
return s3c_init_intc_of(np, interrupt_parent,
s3c2416_ctrl, ARRAY_SIZE(s3c2416_ctrl));
diff --git a/drivers/irqchip/irqchip.c b/drivers/irqchip/irqchip.c
index cad3e2495552..0fe2f718d81c 100644
--- a/drivers/irqchip/irqchip.c
+++ b/drivers/irqchip/irqchip.c
@@ -19,11 +19,11 @@
* special section.
*/
static const struct of_device_id
-irqchip_of_match_end __used __section(__irqchip_of_end);
+irqchip_of_match_end __used __section(__irqchip_of_table_end);
-extern struct of_device_id __irqchip_begin[];
+extern struct of_device_id __irqchip_of_table[];
void __init irqchip_init(void)
{
- of_irq_init(__irqchip_begin);
+ of_irq_init(__irqchip_of_table);
}
diff --git a/drivers/irqchip/irqchip.h b/drivers/irqchip/irqchip.h
index e445ba2d6add..0f6486d4f1b0 100644
--- a/drivers/irqchip/irqchip.h
+++ b/drivers/irqchip/irqchip.h
@@ -11,6 +11,8 @@
#ifndef _IRQCHIP_H
#define _IRQCHIP_H
+#include <linux/of.h>
+
/*
* This macro must be used by the different irqchip drivers to declare
* the association between their DT compatible string and their
@@ -21,9 +23,6 @@
* @compstr: compatible string of the irqchip driver
* @fn: initialization function
*/
-#define IRQCHIP_DECLARE(name,compstr,fn) \
- static const struct of_device_id irqchip_of_match_##name \
- __used __section(__irqchip_of_table) \
- = { .compatible = compstr, .data = fn }
+#define IRQCHIP_DECLARE(name, compat, fn) OF_DECLARE_2(irqchip, name, compat, fn)
#endif
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index 39e717797cc0..089841ca180f 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -479,6 +479,8 @@ config LEDS_OT200
This option enables support for the LEDs on the Bachmann OT200.
Say Y to enable LEDs on the Bachmann OT200.
+comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)"
+
config LEDS_BLINKM
tristate "LED support for the BlinkM I2C RGB LED"
depends on LEDS_CLASS
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index 1bdc0e7e8b79..11d2bea23b02 100644
--- a/drivers/media/dvb-core/dvb-usb-ids.h
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
@@ -356,11 +356,13 @@
#define USB_PID_ELGATO_EYETV_DTT_2 0x003f
#define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020
#define USB_PID_ELGATO_EYETV_SAT 0x002a
+#define USB_PID_ELGATO_EYETV_SAT_V2 0x0025
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001
#define USB_PID_FRIIO_WHITE 0x0001
#define USB_PID_TVWAY_PLUS 0x0002
#define USB_PID_SVEON_STV20 0xe39d
+#define USB_PID_SVEON_STV20_RTL2832U 0xd39d
#define USB_PID_SVEON_STV22 0xe401
#define USB_PID_SVEON_STV22_IT9137 0xe411
#define USB_PID_AZUREWAVE_AZ6027 0x3275
@@ -375,4 +377,5 @@
#define USB_PID_CTVDIGDUAL_V2 0xe410
#define USB_PID_PCTV_2002E 0x025c
#define USB_PID_PCTV_2002E_SE 0x025d
+#define USB_PID_SVEON_STV27 0xd3af
#endif
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 025fc5496bfc..1469d44acb22 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -446,6 +446,13 @@ config DVB_RTL2832
help
Say Y when you want to support this frontend.
+config DVB_SI2168
+ tristate "Silicon Labs Si2168"
+ depends on DVB_CORE && I2C && I2C_MUX
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y when you want to support this frontend.
+
comment "DVB-C (cable) frontends"
depends on DVB_CORE
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index 282aba2fe8db..dda0bee36f29 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -78,6 +78,7 @@ obj-$(CONFIG_DVB_AF9013) += af9013.o
obj-$(CONFIG_DVB_CX24116) += cx24116.o
obj-$(CONFIG_DVB_CX24117) += cx24117.o
obj-$(CONFIG_DVB_SI21XX) += si21xx.o
+obj-$(CONFIG_DVB_SI2168) += si2168.o
obj-$(CONFIG_DVB_STV0288) += stv0288.o
obj-$(CONFIG_DVB_STB6000) += stb6000.o
obj-$(CONFIG_DVB_S921) += s921.o
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
new file mode 100644
index 000000000000..8637d2ed7623
--- /dev/null
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -0,0 +1,760 @@
+/*
+ * Silicon Labs Si2168 DVB-T/T2/C demodulator driver
+ *
+ * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "si2168_priv.h"
+
+static const struct dvb_frontend_ops si2168_ops;
+
+/* execute firmware command */
+static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd)
+{
+ int ret;
+ unsigned long timeout;
+
+ mutex_lock(&s->i2c_mutex);
+
+ if (cmd->wlen) {
+ /* write cmd and args for firmware */
+ ret = i2c_master_send(s->client, cmd->args, cmd->wlen);
+ if (ret < 0) {
+ goto err_mutex_unlock;
+ } else if (ret != cmd->wlen) {
+ ret = -EREMOTEIO;
+ goto err_mutex_unlock;
+ }
+ }
+
+ if (cmd->rlen) {
+ /* wait cmd execution terminate */
+ #define TIMEOUT 50
+ timeout = jiffies + msecs_to_jiffies(TIMEOUT);
+ while (!time_after(jiffies, timeout)) {
+ ret = i2c_master_recv(s->client, cmd->args, cmd->rlen);
+ if (ret < 0) {
+ goto err_mutex_unlock;
+ } else if (ret != cmd->rlen) {
+ ret = -EREMOTEIO;
+ goto err_mutex_unlock;
+ }
+
+ /* firmware ready? */
+ if ((cmd->args[0] >> 7) & 0x01)
+ break;
+ }
+
+ dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n",
+ __func__,
+ jiffies_to_msecs(jiffies) -
+ (jiffies_to_msecs(timeout) - TIMEOUT));
+
+ if (!(cmd->args[0] >> 7) & 0x01) {
+ ret = -ETIMEDOUT;
+ goto err_mutex_unlock;
+ }
+ }
+
+ ret = 0;
+
+err_mutex_unlock:
+ mutex_unlock(&s->i2c_mutex);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct si2168 *s = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ struct si2168_cmd cmd;
+
+ *status = 0;
+
+ if (!s->active) {
+ ret = -EAGAIN;
+ goto err;
+ }
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ cmd.args[0] = 0xa0;
+ cmd.args[1] = 0x01;
+ cmd.wlen = 2;
+ cmd.rlen = 13;
+ break;
+ case SYS_DVBC_ANNEX_A:
+ cmd.args[0] = 0x90;
+ cmd.args[1] = 0x01;
+ cmd.wlen = 2;
+ cmd.rlen = 9;
+ break;
+ case SYS_DVBT2:
+ cmd.args[0] = 0x50;
+ cmd.args[1] = 0x01;
+ cmd.wlen = 2;
+ cmd.rlen = 14;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ /*
+ * Possible values seen, in order from strong signal to weak:
+ * 16 0001 0110 full lock
+ * 1e 0001 1110 partial lock
+ * 1a 0001 1010 partial lock
+ * 18 0001 1000 no lock
+ *
+ * [b3:b1] lock bits
+ * [b4] statistics ready? Set in a few secs after lock is gained.
+ */
+
+ switch ((cmd.args[2] >> 1) & 0x03) {
+ case 0x01:
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
+ break;
+ case 0x03:
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+ FE_HAS_SYNC | FE_HAS_LOCK;
+ break;
+ }
+
+ s->fe_status = *status;
+
+ dev_dbg(&s->client->dev, "%s: status=%02x args=%*ph\n",
+ __func__, *status, cmd.rlen, cmd.args);
+
+ return 0;
+err:
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int si2168_set_frontend(struct dvb_frontend *fe)
+{
+ struct si2168 *s = fe->demodulator_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ struct si2168_cmd cmd;
+ u8 bandwidth, delivery_system;
+
+ dev_dbg(&s->client->dev,
+ "%s: delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u\n",
+ __func__, c->delivery_system, c->modulation,
+ c->frequency, c->bandwidth_hz, c->symbol_rate,
+ c->inversion);
+
+ if (!s->active) {
+ ret = -EAGAIN;
+ goto err;
+ }
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ delivery_system = 0x20;
+ break;
+ case SYS_DVBC_ANNEX_A:
+ delivery_system = 0x30;
+ break;
+ case SYS_DVBT2:
+ delivery_system = 0x70;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (c->bandwidth_hz <= 5000000)
+ bandwidth = 0x05;
+ else if (c->bandwidth_hz <= 6000000)
+ bandwidth = 0x06;
+ else if (c->bandwidth_hz <= 7000000)
+ bandwidth = 0x07;
+ else if (c->bandwidth_hz <= 8000000)
+ bandwidth = 0x08;
+ else if (c->bandwidth_hz <= 9000000)
+ bandwidth = 0x09;
+ else if (c->bandwidth_hz <= 10000000)
+ bandwidth = 0x0a;
+ else
+ bandwidth = 0x0f;
+
+ /* program tuner */
+ if (fe->ops.tuner_ops.set_params) {
+ ret = fe->ops.tuner_ops.set_params(fe);
+ if (ret)
+ goto err;
+ }
+
+ memcpy(cmd.args, "\x88\x02\x02\x02\x02", 5);
+ cmd.wlen = 5;
+ cmd.rlen = 5;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ /* that has no big effect */
+ if (c->delivery_system == SYS_DVBT)
+ memcpy(cmd.args, "\x89\x21\x06\x11\xff\x98", 6);
+ else if (c->delivery_system == SYS_DVBC_ANNEX_A)
+ memcpy(cmd.args, "\x89\x21\x06\x11\x89\xf0", 6);
+ else if (c->delivery_system == SYS_DVBT2)
+ memcpy(cmd.args, "\x89\x21\x06\x11\x89\x20", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 3;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x51\x03", 2);
+ cmd.wlen = 2;
+ cmd.rlen = 12;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x12\x08\x04", 3);
+ cmd.wlen = 3;
+ cmd.rlen = 3;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x01\x04\x00\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x03\x10\x17\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x02\x10\x15\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x0c\x10\x12\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x06\x10\x24\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x0b\x10\x88\x13", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x07\x10\x00\x24", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x0a\x10\x00\x00", 6);
+ cmd.args[4] = delivery_system | bandwidth;
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x04\x10\x15\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x05\x10\xa1\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x0f\x10\x10\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x0d\x10\xd0\x02", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x01\x10\x00\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x18", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x15", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x04\x03\x00\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x03\x03\x00\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x08\x03\x00\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x07\x03\x01\x02", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x06\x03\x00\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x05\x03\x00\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x01\x03\x0c\x40", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x01\x10\x16\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ memcpy(cmd.args, "\x14\x00\x01\x12\x00\x00", 6);
+ cmd.wlen = 6;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ cmd.args[0] = 0x85;
+ cmd.wlen = 1;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ s->delivery_system = c->delivery_system;
+
+ return 0;
+err:
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int si2168_init(struct dvb_frontend *fe)
+{
+ struct si2168 *s = fe->demodulator_priv;
+ int ret, len, remaining;
+ const struct firmware *fw = NULL;
+ u8 *fw_file = SI2168_FIRMWARE;
+ const unsigned int i2c_wr_max = 8;
+ struct si2168_cmd cmd;
+
+ dev_dbg(&s->client->dev, "%s:\n", __func__);
+
+ cmd.args[0] = 0x13;
+ cmd.wlen = 1;
+ cmd.rlen = 0;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ cmd.args[0] = 0xc0;
+ cmd.args[1] = 0x12;
+ cmd.args[2] = 0x00;
+ cmd.args[3] = 0x0c;
+ cmd.args[4] = 0x00;
+ cmd.args[5] = 0x0d;
+ cmd.args[6] = 0x16;
+ cmd.args[7] = 0x00;
+ cmd.args[8] = 0x00;
+ cmd.args[9] = 0x00;
+ cmd.args[10] = 0x00;
+ cmd.args[11] = 0x00;
+ cmd.args[12] = 0x00;
+ cmd.wlen = 13;
+ cmd.rlen = 0;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ cmd.args[0] = 0xc0;
+ cmd.args[1] = 0x06;
+ cmd.args[2] = 0x01;
+ cmd.args[3] = 0x0f;
+ cmd.args[4] = 0x00;
+ cmd.args[5] = 0x20;
+ cmd.args[6] = 0x20;
+ cmd.args[7] = 0x01;
+ cmd.wlen = 8;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ cmd.args[0] = 0x02;
+ cmd.wlen = 1;
+ cmd.rlen = 13;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ cmd.args[0] = 0x05;
+ cmd.args[1] = 0x00;
+ cmd.args[2] = 0xaa;
+ cmd.args[3] = 0x4d;
+ cmd.args[4] = 0x56;
+ cmd.args[5] = 0x40;
+ cmd.args[6] = 0x00;
+ cmd.args[7] = 0x00;
+ cmd.wlen = 8;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ /* cold state - try to download firmware */
+ dev_info(&s->client->dev, "%s: found a '%s' in cold state\n",
+ KBUILD_MODNAME, si2168_ops.info.name);
+
+ /* request the firmware, this will block and timeout */
+ ret = request_firmware(&fw, fw_file, &s->client->dev);
+ if (ret) {
+ dev_err(&s->client->dev, "%s: firmare file '%s' not found\n",
+ KBUILD_MODNAME, fw_file);
+ goto err;
+ }
+
+ dev_info(&s->client->dev, "%s: downloading firmware from file '%s'\n",
+ KBUILD_MODNAME, fw_file);
+
+ for (remaining = fw->size; remaining > 0; remaining -= i2c_wr_max) {
+ len = remaining;
+ if (len > i2c_wr_max)
+ len = i2c_wr_max;
+
+ memcpy(cmd.args, &fw->data[fw->size - remaining], len);
+ cmd.wlen = len;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret) {
+ dev_err(&s->client->dev,
+ "%s: firmware download failed=%d\n",
+ KBUILD_MODNAME, ret);
+ goto err;
+ }
+ }
+
+ release_firmware(fw);
+ fw = NULL;
+
+ cmd.args[0] = 0x01;
+ cmd.args[1] = 0x01;
+ cmd.wlen = 2;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ dev_info(&s->client->dev, "%s: found a '%s' in warm state\n",
+ KBUILD_MODNAME, si2168_ops.info.name);
+
+ s->active = true;
+
+ return 0;
+err:
+ if (fw)
+ release_firmware(fw);
+
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int si2168_sleep(struct dvb_frontend *fe)
+{
+ struct si2168 *s = fe->demodulator_priv;
+
+ dev_dbg(&s->client->dev, "%s:\n", __func__);
+
+ s->active = false;
+
+ return 0;
+}
+
+static int si2168_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *s)
+{
+ s->min_delay_ms = 900;
+
+ return 0;
+}
+
+/*
+ * I2C gate logic
+ * We must use unlocked i2c_transfer() here because I2C lock is already taken
+ * by tuner driver.
+ */
+static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
+{
+ struct si2168 *s = mux_priv;
+ int ret;
+ struct i2c_msg gate_open_msg = {
+ .addr = s->client->addr,
+ .flags = 0,
+ .len = 3,
+ .buf = "\xc0\x0d\x01",
+ };
+
+ mutex_lock(&s->i2c_mutex);
+
+ /* open tuner I2C gate */
+ ret = __i2c_transfer(s->client->adapter, &gate_open_msg, 1);
+ if (ret != 1) {
+ dev_warn(&s->client->dev, "%s: i2c write failed=%d\n",
+ KBUILD_MODNAME, ret);
+ if (ret >= 0)
+ ret = -EREMOTEIO;
+ } else {
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan)
+{
+ struct si2168 *s = mux_priv;
+ int ret;
+ struct i2c_msg gate_close_msg = {
+ .addr = s->client->addr,
+ .flags = 0,
+ .len = 3,
+ .buf = "\xc0\x0d\x00",
+ };
+
+ /* close tuner I2C gate */
+ ret = __i2c_transfer(s->client->adapter, &gate_close_msg, 1);
+ if (ret != 1) {
+ dev_warn(&s->client->dev, "%s: i2c write failed=%d\n",
+ KBUILD_MODNAME, ret);
+ if (ret >= 0)
+ ret = -EREMOTEIO;
+ } else {
+ ret = 0;
+ }
+
+ mutex_unlock(&s->i2c_mutex);
+
+ return ret;
+}
+
+static const struct dvb_frontend_ops si2168_ops = {
+ .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A},
+ .info = {
+ .name = "Silicon Labs Si2168",
+ .caps = FE_CAN_FEC_1_2 |
+ FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 |
+ FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK |
+ FE_CAN_QAM_16 |
+ FE_CAN_QAM_32 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 |
+ FE_CAN_QAM_256 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO |
+ FE_CAN_MUTE_TS |
+ FE_CAN_2G_MODULATION
+ },
+
+ .get_tune_settings = si2168_get_tune_settings,
+
+ .init = si2168_init,
+ .sleep = si2168_sleep,
+
+ .set_frontend = si2168_set_frontend,
+
+ .read_status = si2168_read_status,
+};
+
+static int si2168_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct si2168_config *config = client->dev.platform_data;
+ struct si2168 *s;
+ int ret;
+ struct si2168_cmd cmd;
+
+ dev_dbg(&client->dev, "%s:\n", __func__);
+
+ s = kzalloc(sizeof(struct si2168), GFP_KERNEL);
+ if (!s) {
+ ret = -ENOMEM;
+ dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+ goto err;
+ }
+
+ s->client = client;
+ mutex_init(&s->i2c_mutex);
+
+ /* check if the demod is there */
+ cmd.wlen = 0;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ /* create mux i2c adapter for tuner */
+ s->adapter = i2c_add_mux_adapter(client->adapter, &client->dev, s,
+ 0, 0, 0, si2168_select, si2168_deselect);
+ if (s->adapter == NULL)
+ goto err;
+
+ /* create dvb_frontend */
+ memcpy(&s->fe.ops, &si2168_ops, sizeof(struct dvb_frontend_ops));
+ s->fe.demodulator_priv = s;
+
+ *config->i2c_adapter = s->adapter;
+ *config->fe = &s->fe;
+
+ i2c_set_clientdata(client, s);
+
+ dev_info(&s->client->dev,
+ "%s: Silicon Labs Si2168 successfully attached\n",
+ KBUILD_MODNAME);
+ return 0;
+err:
+ kfree(s);
+ dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int si2168_remove(struct i2c_client *client)
+{
+ struct si2168 *s = i2c_get_clientdata(client);
+
+ dev_dbg(&client->dev, "%s:\n", __func__);
+
+ i2c_del_mux_adapter(s->adapter);
+
+ s->fe.ops.release = NULL;
+ s->fe.demodulator_priv = NULL;
+
+ kfree(s);
+
+ return 0;
+}
+
+static const struct i2c_device_id si2168_id[] = {
+ {"si2168", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, si2168_id);
+
+static struct i2c_driver si2168_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "si2168",
+ },
+ .probe = si2168_probe,
+ .remove = si2168_remove,
+ .id_table = si2168_id,
+};
+
+module_i2c_driver(si2168_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Silicon Labs Si2168 DVB-T/T2/C demodulator driver");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(SI2168_FIRMWARE);
diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h
new file mode 100644
index 000000000000..3c5b5ab01796
--- /dev/null
+++ b/drivers/media/dvb-frontends/si2168.h
@@ -0,0 +1,39 @@
+/*
+ * Silicon Labs Si2168 DVB-T/T2/C demodulator driver
+ *
+ * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SI2168_H
+#define SI2168_H
+
+#include <linux/dvb/frontend.h>
+/*
+ * I2C address
+ * 0x64
+ */
+struct si2168_config {
+ /*
+ * frontend
+ * returned by driver
+ */
+ struct dvb_frontend **fe;
+
+ /*
+ * tuner I2C adapter
+ * returned by driver
+ */
+ struct i2c_adapter **i2c_adapter;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h
new file mode 100644
index 000000000000..2a343e896f40
--- /dev/null
+++ b/drivers/media/dvb-frontends/si2168_priv.h
@@ -0,0 +1,46 @@
+/*
+ * Silicon Labs Si2168 DVB-T/T2/C demodulator driver
+ *
+ * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SI2168_PRIV_H
+#define SI2168_PRIV_H
+
+#include "si2168.h"
+#include "dvb_frontend.h"
+#include <linux/firmware.h>
+#include <linux/i2c-mux.h>
+
+#define SI2168_FIRMWARE "dvb-demod-si2168-01.fw"
+
+/* state struct */
+struct si2168 {
+ struct i2c_client *client;
+ struct i2c_adapter *adapter;
+ struct mutex i2c_mutex;
+ struct dvb_frontend fe;
+ fe_delivery_system_t delivery_system;
+ fe_status_t fe_status;
+ bool active;
+};
+
+/* firmare command struct */
+#define SI2157_ARGLEN 30
+struct si2168_cmd {
+ u8 args[SI2157_ARGLEN];
+ unsigned wlen;
+ unsigned rlen;
+};
+
+#endif
diff --git a/drivers/media/i2c/ad9389b.c b/drivers/media/i2c/ad9389b.c
index 1b7ecfd88673..fada17566205 100644
--- a/drivers/media/i2c/ad9389b.c
+++ b/drivers/media/i2c/ad9389b.c
@@ -571,35 +571,6 @@ static const struct v4l2_subdev_core_ops ad9389b_core_ops = {
.interrupt_service_routine = ad9389b_isr,
};
-/* ------------------------------ PAD OPS ------------------------------ */
-
-static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
-{
- struct ad9389b_state *state = get_ad9389b_state(sd);
-
- if (edid->pad != 0)
- return -EINVAL;
- if (edid->blocks == 0 || edid->blocks > 256)
- return -EINVAL;
- if (!edid->edid)
- return -EINVAL;
- if (!state->edid.segments) {
- v4l2_dbg(1, debug, sd, "EDID segment 0 not found\n");
- return -ENODATA;
- }
- if (edid->start_block >= state->edid.segments * 2)
- return -E2BIG;
- if (edid->blocks + edid->start_block >= state->edid.segments * 2)
- edid->blocks = state->edid.segments * 2 - edid->start_block;
- memcpy(edid->edid, &state->edid.data[edid->start_block * 128],
- 128 * edid->blocks);
- return 0;
-}
-
-static const struct v4l2_subdev_pad_ops ad9389b_pad_ops = {
- .get_edid = ad9389b_get_edid,
-};
-
/* ------------------------------ VIDEO OPS ------------------------------ */
/* Enable/disable ad9389b output */
@@ -678,6 +649,9 @@ static int ad9389b_g_dv_timings(struct v4l2_subdev *sd,
static int ad9389b_enum_dv_timings(struct v4l2_subdev *sd,
struct v4l2_enum_dv_timings *timings)
{
+ if (timings->pad != 0)
+ return -EINVAL;
+
return v4l2_enum_dv_timings_cap(timings, &ad9389b_timings_cap,
NULL, NULL);
}
@@ -685,6 +659,9 @@ static int ad9389b_enum_dv_timings(struct v4l2_subdev *sd,
static int ad9389b_dv_timings_cap(struct v4l2_subdev *sd,
struct v4l2_dv_timings_cap *cap)
{
+ if (cap->pad != 0)
+ return -EINVAL;
+
*cap = ad9389b_timings_cap;
return 0;
}
@@ -693,10 +670,39 @@ static const struct v4l2_subdev_video_ops ad9389b_video_ops = {
.s_stream = ad9389b_s_stream,
.s_dv_timings = ad9389b_s_dv_timings,
.g_dv_timings = ad9389b_g_dv_timings,
+};
+
+/* ------------------------------ PAD OPS ------------------------------ */
+
+static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+{
+ struct ad9389b_state *state = get_ad9389b_state(sd);
+
+ if (edid->pad != 0)
+ return -EINVAL;
+ if (edid->blocks == 0 || edid->blocks > 256)
+ return -EINVAL;
+ if (!state->edid.segments) {
+ v4l2_dbg(1, debug, sd, "EDID segment 0 not found\n");
+ return -ENODATA;
+ }
+ if (edid->start_block >= state->edid.segments * 2)
+ return -E2BIG;
+ if (edid->blocks + edid->start_block >= state->edid.segments * 2)
+ edid->blocks = state->edid.segments * 2 - edid->start_block;
+ memcpy(edid->edid, &state->edid.data[edid->start_block * 128],
+ 128 * edid->blocks);
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops ad9389b_pad_ops = {
+ .get_edid = ad9389b_get_edid,
.enum_dv_timings = ad9389b_enum_dv_timings,
.dv_timings_cap = ad9389b_dv_timings_cap,
};
+/* ------------------------------ AUDIO OPS ------------------------------ */
+
static int ad9389b_s_audio_stream(struct v4l2_subdev *sd, int enable)
{
v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis"));
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 5e638b159452..ac1cdbe251a3 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -461,6 +461,7 @@ static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_video_ops adv7180_video_ops = {
+ .s_std = adv7180_s_std,
.querystd = adv7180_querystd,
.g_input_status = adv7180_g_input_status,
.s_routing = adv7180_s_routing,
@@ -472,7 +473,6 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = {
};
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
- .s_std = adv7180_s_std,
.s_power = adv7180_s_power,
};
diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c
index d45e0e3a781d..df461b07b2f7 100644
--- a/drivers/media/i2c/adv7183.c
+++ b/drivers/media/i2c/adv7183.c
@@ -501,8 +501,6 @@ static const struct v4l2_ctrl_ops adv7183_ctrl_ops = {
static const struct v4l2_subdev_core_ops adv7183_core_ops = {
.log_status = adv7183_log_status,
- .g_std = adv7183_g_std,
- .s_std = adv7183_s_std,
.reset = adv7183_reset,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = adv7183_g_register,
@@ -511,6 +509,8 @@ static const struct v4l2_subdev_core_ops adv7183_core_ops = {
};
static const struct v4l2_subdev_video_ops adv7183_video_ops = {
+ .g_std = adv7183_g_std,
+ .s_std = adv7183_s_std,
.s_routing = adv7183_s_routing,
.querystd = adv7183_querystd,
.g_input_status = adv7183_g_input_status,
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index 942ca4b99297..f98acf4aafd4 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -597,34 +597,6 @@ static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
return 0;
}
-static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
-{
- struct adv7511_state *state = get_adv7511_state(sd);
-
- if (edid->pad != 0)
- return -EINVAL;
- if ((edid->blocks == 0) || (edid->blocks > 256))
- return -EINVAL;
- if (!edid->edid)
- return -EINVAL;
- if (!state->edid.segments) {
- v4l2_dbg(1, debug, sd, "EDID segment 0 not found\n");
- return -ENODATA;
- }
- if (edid->start_block >= state->edid.segments * 2)
- return -E2BIG;
- if ((edid->blocks + edid->start_block) >= state->edid.segments * 2)
- edid->blocks = state->edid.segments * 2 - edid->start_block;
-
- memcpy(edid->edid, &state->edid.data[edid->start_block * 128],
- 128 * edid->blocks);
- return 0;
-}
-
-static const struct v4l2_subdev_pad_ops adv7511_pad_ops = {
- .get_edid = adv7511_get_edid,
-};
-
static const struct v4l2_subdev_core_ops adv7511_core_ops = {
.log_status = adv7511_log_status,
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -700,12 +672,18 @@ static int adv7511_g_dv_timings(struct v4l2_subdev *sd,
static int adv7511_enum_dv_timings(struct v4l2_subdev *sd,
struct v4l2_enum_dv_timings *timings)
{
+ if (timings->pad != 0)
+ return -EINVAL;
+
return v4l2_enum_dv_timings_cap(timings, &adv7511_timings_cap, NULL, NULL);
}
static int adv7511_dv_timings_cap(struct v4l2_subdev *sd,
struct v4l2_dv_timings_cap *cap)
{
+ if (cap->pad != 0)
+ return -EINVAL;
+
*cap = adv7511_timings_cap;
return 0;
}
@@ -714,8 +692,6 @@ static const struct v4l2_subdev_video_ops adv7511_video_ops = {
.s_stream = adv7511_s_stream,
.s_dv_timings = adv7511_s_dv_timings,
.g_dv_timings = adv7511_g_dv_timings,
- .enum_dv_timings = adv7511_enum_dv_timings,
- .dv_timings_cap = adv7511_dv_timings_cap,
};
/* ------------------------------ AUDIO OPS ------------------------------ */
@@ -797,6 +773,36 @@ static const struct v4l2_subdev_audio_ops adv7511_audio_ops = {
.s_routing = adv7511_s_routing,
};
+/* ---------------------------- PAD OPS ------------------------------------- */
+
+static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
+{
+ struct adv7511_state *state = get_adv7511_state(sd);
+
+ if (edid->pad != 0)
+ return -EINVAL;
+ if ((edid->blocks == 0) || (edid->blocks > 256))
+ return -EINVAL;
+ if (!state->edid.segments) {
+ v4l2_dbg(1, debug, sd, "EDID segment 0 not found\n");
+ return -ENODATA;
+ }
+ if (edid->start_block >= state->edid.segments * 2)
+ return -E2BIG;
+ if ((edid->blocks + edid->start_block) >= state->edid.segments * 2)
+ edid->blocks = state->edid.segments * 2 - edid->start_block;
+
+ memcpy(edid->edid, &state->edid.data[edid->start_block * 128],
+ 128 * edid->blocks);
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops adv7511_pad_ops = {
+ .get_edid = adv7511_get_edid,
+ .enum_dv_timings = adv7511_enum_dv_timings,
+ .dv_timings_cap = adv7511_dv_timings_cap,
+};
+
/* --------------------- SUBDEV OPS --------------------------------------- */
static const struct v4l2_subdev_ops adv7511_ops = {
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 98cc5407f1b1..338baa4c23ef 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -1673,8 +1673,6 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
return -EINVAL;
if (edid->start_block == 1)
edid->blocks = 1;
- if (!edid->edid)
- return -EINVAL;
if (edid->blocks > state->edid.blocks)
edid->blocks = state->edid.blocks;
@@ -1761,8 +1759,6 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
edid->blocks = 2;
return -E2BIG;
}
- if (!edid->edid)
- return -EINVAL;
v4l2_dbg(2, debug, sd, "%s: write EDID pad %d, edid.present = 0x%x\n",
__func__, edid->pad, state->edid.present);
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 636ac08925f6..0d554919cdd5 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -1399,6 +1399,9 @@ static int read_stdi(struct v4l2_subdev *sd, struct stdi_readback *stdi)
static int adv7842_enum_dv_timings(struct v4l2_subdev *sd,
struct v4l2_enum_dv_timings *timings)
{
+ if (timings->pad != 0)
+ return -EINVAL;
+
return v4l2_enum_dv_timings_cap(timings,
adv7842_get_dv_timings_cap(sd), adv7842_check_dv_timings, NULL);
}
@@ -1406,6 +1409,9 @@ static int adv7842_enum_dv_timings(struct v4l2_subdev *sd,
static int adv7842_dv_timings_cap(struct v4l2_subdev *sd,
struct v4l2_dv_timings_cap *cap)
{
+ if (cap->pad != 0)
+ return -EINVAL;
+
*cap = *adv7842_get_dv_timings_cap(sd);
return 0;
}
@@ -2000,6 +2006,7 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
if (irq_status[5] & 0x08) {
v4l2_dbg(1, debug, sd, "%s: irq %s mode\n", __func__,
(io_read(sd, 0x65) & 0x08) ? "HDMI" : "DVI");
+ set_rgb_quantization_range(sd);
if (handled)
*handled = true;
}
@@ -2029,8 +2036,6 @@ static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
return -EINVAL;
if (edid->start_block == 1)
edid->blocks = 1;
- if (!edid->edid)
- return -EINVAL;
switch (edid->pad) {
case ADV7842_EDID_PORT_A:
@@ -2065,8 +2070,6 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
return -EINVAL;
if (e->blocks > 2)
return -E2BIG;
- if (!e->edid)
- return -EINVAL;
/* todo, per edid */
state->aspect_ratio = v4l2_calc_aspect_ratio(e->edid[0x15],
@@ -2610,6 +2613,12 @@ static int adv7842_core_init(struct v4l2_subdev *sd)
disable_input(sd);
+ /*
+ * Disable I2C access to internal EDID ram from HDMI DDC ports
+ * Disable auto edid enable when leaving powerdown mode
+ */
+ rep_write_and_or(sd, 0x77, 0xd3, 0x20);
+
/* power */
io_write(sd, 0x0c, 0x42); /* Power up part and power down VDP */
io_write(sd, 0x15, 0x80); /* Power up pads */
@@ -2690,9 +2699,6 @@ static int adv7842_core_init(struct v4l2_subdev *sd)
enable_input(sd);
- /* disable I2C access to internal EDID ram from HDMI DDC ports */
- rep_write_and_or(sd, 0x77, 0xf3, 0x00);
-
if (pdata->hpa_auto) {
/* HPA auto, HPA 0.5s after Edid set and Cable detect */
hdmi_write(sd, 0x69, 0x5c);
@@ -2869,8 +2875,6 @@ static const struct v4l2_ctrl_ops adv7842_ctrl_ops = {
static const struct v4l2_subdev_core_ops adv7842_core_ops = {
.log_status = adv7842_log_status,
- .g_std = adv7842_g_std,
- .s_std = adv7842_s_std,
.ioctl = adv7842_ioctl,
.interrupt_service_routine = adv7842_isr,
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -2880,14 +2884,14 @@ static const struct v4l2_subdev_core_ops adv7842_core_ops = {
};
static const struct v4l2_subdev_video_ops adv7842_video_ops = {
+ .g_std = adv7842_g_std,
+ .s_std = adv7842_s_std,
.s_routing = adv7842_s_routing,
.querystd = adv7842_querystd,
.g_input_status = adv7842_g_input_status,
.s_dv_timings = adv7842_s_dv_timings,
.g_dv_timings = adv7842_g_dv_timings,
.query_dv_timings = adv7842_query_dv_timings,
- .enum_dv_timings = adv7842_enum_dv_timings,
- .dv_timings_cap = adv7842_dv_timings_cap,
.enum_mbus_fmt = adv7842_enum_mbus_fmt,
.g_mbus_fmt = adv7842_g_mbus_fmt,
.try_mbus_fmt = adv7842_g_mbus_fmt,
@@ -2897,6 +2901,8 @@ static const struct v4l2_subdev_video_ops adv7842_video_ops = {
static const struct v4l2_subdev_pad_ops adv7842_pad_ops = {
.get_edid = adv7842_get_edid,
.set_edid = adv7842_set_edid,
+ .enum_dv_timings = adv7842_enum_dv_timings,
+ .dv_timings_cap = adv7842_dv_timings_cap,
};
static const struct v4l2_subdev_ops adv7842_ops = {
diff --git a/drivers/media/i2c/bt819.c b/drivers/media/i2c/bt819.c
index 369cf6ff88f7..76b334a6a56d 100644
--- a/drivers/media/i2c/bt819.c
+++ b/drivers/media/i2c/bt819.c
@@ -387,10 +387,10 @@ static const struct v4l2_subdev_core_ops bt819_core_ops = {
.s_ctrl = v4l2_subdev_s_ctrl,
.queryctrl = v4l2_subdev_queryctrl,
.querymenu = v4l2_subdev_querymenu,
- .s_std = bt819_s_std,
};
static const struct v4l2_subdev_video_ops bt819_video_ops = {
+ .s_std = bt819_s_std,
.s_routing = bt819_s_routing,
.s_stream = bt819_s_stream,
.querystd = bt819_querystd,
diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
index 2e3771d57354..e453a3ffe7d1 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -5041,8 +5041,6 @@ static const struct v4l2_subdev_core_ops cx25840_core_ops = {
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.queryctrl = v4l2_subdev_queryctrl,
.querymenu = v4l2_subdev_querymenu,
- .s_std = cx25840_s_std,
- .g_std = cx25840_g_std,
.reset = cx25840_reset,
.load_fw = cx25840_load_fw,
.s_io_pin_config = common_s_io_pin_config,
@@ -5067,6 +5065,8 @@ static const struct v4l2_subdev_audio_ops cx25840_audio_ops = {
};
static const struct v4l2_subdev_video_ops cx25840_video_ops = {
+ .s_std = cx25840_s_std,
+ .g_std = cx25840_g_std,
.s_routing = cx25840_s_video_routing,
.s_mbus_fmt = cx25840_s_mbus_fmt,
.s_stream = cx25840_s_stream,
diff --git a/drivers/media/i2c/ks0127.c b/drivers/media/i2c/ks0127.c
index c3e94ae82c03..25b81bc58c81 100644
--- a/drivers/media/i2c/ks0127.c
+++ b/drivers/media/i2c/ks0127.c
@@ -648,11 +648,8 @@ static int ks0127_g_input_status(struct v4l2_subdev *sd, u32 *status)
/* ----------------------------------------------------------------------- */
-static const struct v4l2_subdev_core_ops ks0127_core_ops = {
- .s_std = ks0127_s_std,
-};
-
static const struct v4l2_subdev_video_ops ks0127_video_ops = {
+ .s_std = ks0127_s_std,
.s_routing = ks0127_s_routing,
.s_stream = ks0127_s_stream,
.querystd = ks0127_querystd,
@@ -660,7 +657,6 @@ static const struct v4l2_subdev_video_ops ks0127_video_ops = {
};
static const struct v4l2_subdev_ops ks0127_ops = {
- .core = &ks0127_core_ops,
.video = &ks0127_video_ops,
};
diff --git a/drivers/media/i2c/m5mols/m5mols_capture.c b/drivers/media/i2c/m5mols/m5mols_capture.c
index ab34ccedf31e..1a03d02bd4d1 100644
--- a/drivers/media/i2c/m5mols/m5mols_capture.c
+++ b/drivers/media/i2c/m5mols/m5mols_capture.c
@@ -26,7 +26,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
#include <media/m5mols.h>
-#include <media/s5p_fimc.h>
+#include <media/exynos-fimc.h>
#include "m5mols.h"
#include "m5mols_reg.h"
diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c
index a9110d8bbbcd..2cace7313a22 100644
--- a/drivers/media/i2c/ml86v7667.c
+++ b/drivers/media/i2c/ml86v7667.c
@@ -276,6 +276,7 @@ static const struct v4l2_ctrl_ops ml86v7667_ctrl_ops = {
};
static struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = {
+ .s_std = ml86v7667_s_std,
.querystd = ml86v7667_querystd,
.g_input_status = ml86v7667_g_input_status,
.enum_mbus_fmt = ml86v7667_enum_mbus_fmt,
@@ -286,7 +287,6 @@ static struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = {
};
static struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = {
- .s_std = ml86v7667_s_std,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = ml86v7667_g_register,
.s_register = ml86v7667_s_register,
diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c
index 8190fec68080..4d9c6bc34265 100644
--- a/drivers/media/i2c/msp3400-driver.c
+++ b/drivers/media/i2c/msp3400-driver.c
@@ -649,10 +649,10 @@ static const struct v4l2_subdev_core_ops msp_core_ops = {
.s_ctrl = v4l2_subdev_s_ctrl,
.queryctrl = v4l2_subdev_queryctrl,
.querymenu = v4l2_subdev_querymenu,
- .s_std = msp_s_std,
};
static const struct v4l2_subdev_video_ops msp_video_ops = {
+ .s_std = msp_s_std,
.querystd = msp_querystd,
};
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index 33daace81297..e18797ff7faf 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -647,6 +647,28 @@ static int mt9p031_set_crop(struct v4l2_subdev *subdev,
#define V4L2_CID_BLC_ANALOG_OFFSET (V4L2_CID_USER_BASE | 0x1004)
#define V4L2_CID_BLC_DIGITAL_OFFSET (V4L2_CID_USER_BASE | 0x1005)
+static int mt9p031_restore_blc(struct mt9p031 *mt9p031)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
+ int ret;
+
+ if (mt9p031->blc_auto->cur.val != 0) {
+ ret = mt9p031_set_mode2(mt9p031, 0,
+ MT9P031_READ_MODE_2_ROW_BLC);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (mt9p031->blc_offset->cur.val != 0) {
+ ret = mt9p031_write(client, MT9P031_ROW_BLACK_TARGET,
+ mt9p031->blc_offset->cur.val);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct mt9p031 *mt9p031 =
@@ -655,6 +677,9 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
u16 data;
int ret;
+ if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE)
+ return 0;
+
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
ret = mt9p031_write(client, MT9P031_SHUTTER_WIDTH_UPPER,
@@ -709,18 +734,20 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
MT9P031_READ_MODE_2_ROW_MIR, 0);
case V4L2_CID_TEST_PATTERN:
+ /* The digital side of the Black Level Calibration function must
+ * be disabled when generating a test pattern to avoid artifacts
+ * in the image. Activate (deactivate) the BLC-related controls
+ * when the test pattern is enabled (disabled).
+ */
+ v4l2_ctrl_activate(mt9p031->blc_auto, ctrl->val == 0);
+ v4l2_ctrl_activate(mt9p031->blc_offset, ctrl->val == 0);
+
if (!ctrl->val) {
- /* Restore the black level compensation settings. */
- if (mt9p031->blc_auto->cur.val != 0) {
- ret = mt9p031_s_ctrl(mt9p031->blc_auto);
- if (ret < 0)
- return ret;
- }
- if (mt9p031->blc_offset->cur.val != 0) {
- ret = mt9p031_s_ctrl(mt9p031->blc_offset);
- if (ret < 0)
- return ret;
- }
+ /* Restore the BLC settings. */
+ ret = mt9p031_restore_blc(mt9p031);
+ if (ret < 0)
+ return ret;
+
return mt9p031_write(client, MT9P031_TEST_PATTERN,
MT9P031_TEST_PATTERN_DISABLE);
}
@@ -735,9 +762,7 @@ static int mt9p031_s_ctrl(struct v4l2_ctrl *ctrl)
if (ret < 0)
return ret;
- /* Disable digital black level compensation when using a test
- * pattern.
- */
+ /* Disable digital BLC when generating a test pattern. */
ret = mt9p031_set_mode2(mt9p031, MT9P031_READ_MODE_2_ROW_BLC,
0);
if (ret < 0)
diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c
index 8272c0b9c5bf..04e9e55018a5 100644
--- a/drivers/media/i2c/saa6752hs.c
+++ b/drivers/media/i2c/saa6752hs.c
@@ -643,10 +643,10 @@ static const struct v4l2_ctrl_ops saa6752hs_ctrl_ops = {
static const struct v4l2_subdev_core_ops saa6752hs_core_ops = {
.init = saa6752hs_init,
- .s_std = saa6752hs_s_std,
};
static const struct v4l2_subdev_video_ops saa6752hs_video_ops = {
+ .s_std = saa6752hs_s_std,
.s_mbus_fmt = saa6752hs_s_mbus_fmt,
.try_mbus_fmt = saa6752hs_try_mbus_fmt,
.g_mbus_fmt = saa6752hs_g_mbus_fmt,
diff --git a/drivers/media/i2c/saa7110.c b/drivers/media/i2c/saa7110.c
index ac43e929a1d6..99689ee57d7e 100644
--- a/drivers/media/i2c/saa7110.c
+++ b/drivers/media/i2c/saa7110.c
@@ -365,10 +365,10 @@ static const struct v4l2_subdev_core_ops saa7110_core_ops = {
.s_ctrl = v4l2_subdev_s_ctrl,
.queryctrl = v4l2_subdev_queryctrl,
.querymenu = v4l2_subdev_querymenu,
- .s_std = saa7110_s_std,
};
static const struct v4l2_subdev_video_ops saa7110_video_ops = {
+ .s_std = saa7110_s_std,
.s_routing = saa7110_s_routing,
.s_stream = saa7110_s_stream,
.querystd = saa7110_querystd,
diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c
index afdbcb045cee..35a44648150e 100644
--- a/drivers/media/i2c/saa7115.c
+++ b/drivers/media/i2c/saa7115.c
@@ -1582,7 +1582,6 @@ static const struct v4l2_subdev_core_ops saa711x_core_ops = {
.s_ctrl = v4l2_subdev_s_ctrl,
.queryctrl = v4l2_subdev_queryctrl,
.querymenu = v4l2_subdev_querymenu,
- .s_std = saa711x_s_std,
.reset = saa711x_reset,
.s_gpio = saa711x_s_gpio,
#ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -1601,6 +1600,7 @@ static const struct v4l2_subdev_audio_ops saa711x_audio_ops = {
};
static const struct v4l2_subdev_video_ops saa711x_video_ops = {
+ .s_std = saa711x_s_std,
.s_routing = saa711x_s_routing,
.s_crystal_freq = saa711x_s_crystal_freq,
.s_mbus_fmt = saa711x_s_mbus_fmt,
diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c
index 401ca114ab99..6922a9f9a5cd 100644
--- a/drivers/media/i2c/saa717x.c
+++ b/drivers/media/i2c/saa717x.c
@@ -1198,7 +1198,6 @@ static const struct v4l2_subdev_core_ops saa717x_core_ops = {
.g_register = saa717x_g_register,
.s_register = saa717x_s_register,
#endif
- .s_std = saa717x_s_std,
.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
@@ -1216,6 +1215,7 @@ static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = {
};
static const struct v4l2_subdev_video_ops saa717x_video_ops = {
+ .s_std = saa717x_s_std,
.s_routing = saa717x_s_video_routing,
.s_mbus_fmt = saa717x_s_mbus_fmt,
.s_stream = saa717x_s_stream,
diff --git a/drivers/media/i2c/saa7191.c b/drivers/media/i2c/saa7191.c
index 606a4baf944d..8e9699268a63 100644
--- a/drivers/media/i2c/saa7191.c
+++ b/drivers/media/i2c/saa7191.c
@@ -573,10 +573,10 @@ static int saa7191_g_input_status(struct v4l2_subdev *sd, u32 *status)
static const struct v4l2_subdev_core_ops saa7191_core_ops = {
.g_ctrl = saa7191_g_ctrl,
.s_ctrl = saa7191_s_ctrl,
- .s_std = saa7191_s_std,
};
static const struct v4l2_subdev_video_ops saa7191_video_ops = {
+ .s_std = saa7191_s_std,
.s_routing = saa7191_s_routing,
.querystd = saa7191_querystd,
.g_input_status = saa7191_g_input_status,
diff --git a/drivers/media/i2c/smiapp-pll.h b/drivers/media/i2c/smiapp-pll.h
index a4a649834a18..5ce2b61da3c5 100644
--- a/drivers/media/i2c/smiapp-pll.h
+++ b/drivers/media/i2c/smiapp-pll.h
@@ -46,7 +46,7 @@ struct smiapp_pll {
uint8_t bus_width;
} parallel;
};
- uint8_t flags;
+ unsigned long flags;
uint8_t binning_horizontal;
uint8_t binning_vertical;
uint8_t scale_m;
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 8741cae9c9f2..06fb03291d59 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -606,7 +606,7 @@ static int smiapp_get_limits(struct smiapp_sensor *sensor, int const *limit,
if (rval)
return rval;
sensor->limits[limit[i]] = val;
- dev_dbg(&client->dev, "0x%8.8x \"%s\" = %d, 0x%x\n",
+ dev_dbg(&client->dev, "0x%8.8x \"%s\" = %u, 0x%x\n",
smiapp_reg_limits[limit[i]].addr,
smiapp_reg_limits[limit[i]].what, val, val);
}
@@ -741,8 +741,8 @@ static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor)
if (rval)
return rval;
- dev_dbg(&client->dev, "bpp %d, compressed %d\n",
- fmt >> 8, (u8)fmt);
+ dev_dbg(&client->dev, "%u: bpp %u, compressed %u\n",
+ i, fmt >> 8, (u8)fmt);
for (j = 0; j < ARRAY_SIZE(smiapp_csi_data_formats); j++) {
const struct smiapp_csi_data_format *f =
@@ -1128,7 +1128,7 @@ static int smiapp_power_on(struct smiapp_sensor *sensor)
}
usleep_range(1000, 1000);
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ if (gpio_is_valid(sensor->platform_data->xshutdown))
gpio_set_value(sensor->platform_data->xshutdown, 1);
sleep = SMIAPP_RESET_DELAY(sensor->platform_data->ext_clk);
@@ -1238,7 +1238,7 @@ static int smiapp_power_on(struct smiapp_sensor *sensor)
return 0;
out_cci_addr_fail:
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ if (gpio_is_valid(sensor->platform_data->xshutdown))
gpio_set_value(sensor->platform_data->xshutdown, 0);
if (sensor->platform_data->set_xclk)
sensor->platform_data->set_xclk(&sensor->src->sd, 0);
@@ -1264,7 +1264,7 @@ static void smiapp_power_off(struct smiapp_sensor *sensor)
SMIAPP_REG_U8_SOFTWARE_RESET,
SMIAPP_SOFTWARE_RESET);
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ if (gpio_is_valid(sensor->platform_data->xshutdown))
gpio_set_value(sensor->platform_data->xshutdown, 0);
if (sensor->platform_data->set_xclk)
sensor->platform_data->set_xclk(&sensor->src->sd, 0);
@@ -1766,7 +1766,7 @@ static void smiapp_set_compose_binner(struct v4l2_subdev *subdev,
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
unsigned int i;
unsigned int binh = 1, binv = 1;
- unsigned int best = scaling_goodness(
+ int best = scaling_goodness(
subdev,
crops[SMIAPP_PAD_SINK]->width, sel->r.width,
crops[SMIAPP_PAD_SINK]->height, sel->r.height, sel->flags);
@@ -2355,17 +2355,17 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
unsigned int i;
int rval;
- sensor->vana = devm_regulator_get(&client->dev, "VANA");
+ sensor->vana = devm_regulator_get(&client->dev, "vana");
if (IS_ERR(sensor->vana)) {
dev_err(&client->dev, "could not get regulator for vana\n");
- return -ENODEV;
+ return PTR_ERR(sensor->vana);
}
if (!sensor->platform_data->set_xclk) {
sensor->ext_clk = devm_clk_get(&client->dev, "ext_clk");
if (IS_ERR(sensor->ext_clk)) {
dev_err(&client->dev, "could not get clock\n");
- return -ENODEV;
+ return PTR_ERR(sensor->ext_clk);
}
rval = clk_set_rate(sensor->ext_clk,
@@ -2374,18 +2374,19 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
dev_err(&client->dev,
"unable to set clock freq to %u\n",
sensor->platform_data->ext_clk);
- return -ENODEV;
+ return rval;
}
}
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) {
- if (devm_gpio_request_one(&client->dev,
- sensor->platform_data->xshutdown, 0,
- "SMIA++ xshutdown") != 0) {
+ if (gpio_is_valid(sensor->platform_data->xshutdown)) {
+ rval = devm_gpio_request_one(
+ &client->dev, sensor->platform_data->xshutdown, 0,
+ "SMIA++ xshutdown");
+ if (rval < 0) {
dev_err(&client->dev,
"unable to acquire reset gpio %d\n",
sensor->platform_data->xshutdown);
- return -ENODEV;
+ return rval;
}
}
@@ -2423,6 +2424,12 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP |
SMIAPP_IMAGE_ORIENTATION_VFLIP;
+ rval = smiapp_call_quirk(sensor, limits);
+ if (rval) {
+ dev_err(&client->dev, "limits quirks failed\n");
+ goto out_power_off;
+ }
+
rval = smiapp_get_mbus_formats(sensor);
if (rval) {
rval = -ENODEV;
@@ -2483,12 +2490,6 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
}
}
- rval = smiapp_call_quirk(sensor, limits);
- if (rval) {
- dev_err(&client->dev, "limits quirks failed\n");
- goto out_nvm_release;
- }
-
/* We consider this as profile 0 sensor if any of these are zero. */
if (!sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV] ||
!sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV] ||
@@ -2543,8 +2544,9 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
}
snprintf(this->sd.name,
- sizeof(this->sd.name), "%s %s",
- sensor->minfo.name, _this->name);
+ sizeof(this->sd.name), "%s %d-%4.4x %s",
+ sensor->minfo.name, i2c_adapter_id(client->adapter),
+ client->addr, _this->name);
this->sink_fmt.width =
sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
@@ -2616,12 +2618,11 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
pll->bus_type = SMIAPP_PLL_BUS_TYPE_CSI2;
pll->csi2.lanes = sensor->platform_data->lanes;
pll->ext_clk_freq_hz = sensor->platform_data->ext_clk;
+ pll->flags = smiapp_call_quirk(sensor, pll_flags);
+
/* Profile 0 sensors have no separate OP clock branch. */
if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS;
- if (smiapp_needs_quirk(sensor,
- SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE))
- pll->flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE;
pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
rval = smiapp_update_mode(sensor);
@@ -2830,7 +2831,7 @@ static int smiapp_remove(struct i2c_client *client)
unsigned int i;
if (sensor->power_count) {
- if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
+ if (gpio_is_valid(sensor->platform_data->xshutdown))
gpio_set_value(sensor->platform_data->xshutdown, 0);
if (sensor->platform_data->set_xclk)
sensor->platform_data->set_xclk(&sensor->src->sd, 0);
diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c
index bb8c506e0e3d..e0bee8752122 100644
--- a/drivers/media/i2c/smiapp/smiapp-quirk.c
+++ b/drivers/media/i2c/smiapp/smiapp-quirk.c
@@ -28,7 +28,7 @@
static int smiapp_write_8(struct smiapp_sensor *sensor, u16 reg, u8 val)
{
- return smiapp_write(sensor, (SMIA_REG_8BIT << 16) | reg, val);
+ return smiapp_write(sensor, SMIAPP_REG_MK_U8(reg), val);
}
static int smiapp_write_8s(struct smiapp_sensor *sensor,
@@ -61,52 +61,6 @@ void smiapp_replace_limit(struct smiapp_sensor *sensor,
sensor->limits[limit] = val;
}
-bool smiapp_quirk_reg(struct smiapp_sensor *sensor,
- u32 reg, u32 *val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- const struct smia_reg *sreg;
-
- if (!sensor->minfo.quirk)
- return false;
-
- sreg = sensor->minfo.quirk->regs;
-
- if (!sreg)
- return false;
-
- while (sreg->type) {
- u16 type = reg >> 16;
- u16 reg16 = reg;
-
- if (sreg->type != type || sreg->reg != reg16) {
- sreg++;
- continue;
- }
-
- switch ((u8)type) {
- case SMIA_REG_8BIT:
- dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%2.2x\n",
- reg, sreg->val);
- break;
- case SMIA_REG_16BIT:
- dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%4.4x\n",
- reg, sreg->val);
- break;
- case SMIA_REG_32BIT:
- dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%8.8x\n",
- reg, sreg->val);
- break;
- }
-
- *val = sreg->val;
-
- return true;
- }
-
- return false;
-}
-
static int jt8ew9_limits(struct smiapp_sensor *sensor)
{
if (sensor->minfo.revision_number_major < 0x03)
@@ -266,12 +220,17 @@ static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor)
return smiapp_write_8(sensor, 0x3328, 0x80);
}
+static unsigned long jt8ev1_pll_flags(struct smiapp_sensor *sensor)
+{
+ return SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE;
+}
+
const struct smiapp_quirk smiapp_jt8ev1_quirk = {
.limits = jt8ev1_limits,
.post_poweron = jt8ev1_post_poweron,
.pre_streamon = jt8ev1_pre_streamon,
.post_streamoff = jt8ev1_post_streamoff,
- .flags = SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE,
+ .pll_flags = jt8ev1_pll_flags,
};
static int tcm8500md_limits(struct smiapp_sensor *sensor)
diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.h b/drivers/media/i2c/smiapp/smiapp-quirk.h
index 504a6d80ced5..46e9ea8bfa08 100644
--- a/drivers/media/i2c/smiapp/smiapp-quirk.h
+++ b/drivers/media/i2c/smiapp/smiapp-quirk.h
@@ -35,19 +35,30 @@ struct smiapp_sensor;
* @post_poweron: Called always after the sensor has been fully powered on.
* @pre_streamon: Called just before streaming is enabled.
* @post_streamon: Called right after stopping streaming.
+ * @reg_access: Register access quirk. The quirk may divert the access
+ * to another register, or no register at all.
+ *
+ * @write: Is this read (false) or write (true) access?
+ * @reg: Pointer to the register to access
+ * @value: Register value, set by the caller on write, or
+ * by the quirk on read
+ *
+ * @return: 0 on success, -ENOIOCTLCMD if no register
+ * access may be done by the caller (default read
+ * value is zero), else negative error code on error
*/
struct smiapp_quirk {
int (*limits)(struct smiapp_sensor *sensor);
int (*post_poweron)(struct smiapp_sensor *sensor);
int (*pre_streamon)(struct smiapp_sensor *sensor);
int (*post_streamoff)(struct smiapp_sensor *sensor);
- const struct smia_reg *regs;
+ unsigned long (*pll_flags)(struct smiapp_sensor *sensor);
+ int (*reg_access)(struct smiapp_sensor *sensor, bool write, u32 *reg,
+ u32 *val);
unsigned long flags;
};
-/* op pix clock is for all lanes in total normally */
-#define SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0)
-#define SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY (1 << 1)
+#define SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY (1 << 0)
struct smiapp_reg_8 {
u16 reg;
@@ -56,12 +67,9 @@ struct smiapp_reg_8 {
void smiapp_replace_limit(struct smiapp_sensor *sensor,
u32 limit, u32 val);
-bool smiapp_quirk_reg(struct smiapp_sensor *sensor,
- u32 reg, u32 *val);
-#define SMIAPP_MK_QUIRK_REG(_reg, _val) \
+#define SMIAPP_MK_QUIRK_REG_8(_reg, _val) \
{ \
- .type = (_reg >> 16), \
.reg = (u16)_reg, \
.val = _val, \
}
diff --git a/drivers/media/i2c/smiapp/smiapp-reg-defs.h b/drivers/media/i2c/smiapp/smiapp-reg-defs.h
index 3aa0ca948d87..c488ef028074 100644
--- a/drivers/media/i2c/smiapp/smiapp-reg-defs.h
+++ b/drivers/media/i2c/smiapp/smiapp-reg-defs.h
@@ -21,11 +21,11 @@
* 02110-1301 USA
*
*/
-#define SMIAPP_REG_MK_U8(r) ((SMIA_REG_8BIT << 16) | (r))
-#define SMIAPP_REG_MK_U16(r) ((SMIA_REG_16BIT << 16) | (r))
-#define SMIAPP_REG_MK_U32(r) ((SMIA_REG_32BIT << 16) | (r))
+#define SMIAPP_REG_MK_U8(r) ((SMIAPP_REG_8BIT << 16) | (r))
+#define SMIAPP_REG_MK_U16(r) ((SMIAPP_REG_16BIT << 16) | (r))
+#define SMIAPP_REG_MK_U32(r) ((SMIAPP_REG_32BIT << 16) | (r))
-#define SMIAPP_REG_MK_F32(r) (SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | (r))
+#define SMIAPP_REG_MK_F32(r) (SMIAPP_REG_FLAG_FLOAT | (SMIAPP_REG_32BIT << 16) | (r))
#define SMIAPP_REG_U16_MODEL_ID SMIAPP_REG_MK_U16(0x0000)
#define SMIAPP_REG_U8_REVISION_NUMBER_MAJOR SMIAPP_REG_MK_U8(0x0002)
diff --git a/drivers/media/i2c/smiapp/smiapp-regs.c b/drivers/media/i2c/smiapp/smiapp-regs.c
index 4fac32cfcb3f..a2098007fb70 100644
--- a/drivers/media/i2c/smiapp/smiapp-regs.c
+++ b/drivers/media/i2c/smiapp/smiapp-regs.c
@@ -114,14 +114,14 @@ static int ____smiapp_read(struct smiapp_sensor *sensor, u16 reg,
*val = 0;
/* high byte comes first */
switch (len) {
- case SMIA_REG_32BIT:
+ case SMIAPP_REG_32BIT:
*val = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) +
data[3];
break;
- case SMIA_REG_16BIT:
+ case SMIAPP_REG_16BIT:
*val = (data[0] << 8) + data[1];
break;
- case SMIA_REG_8BIT:
+ case SMIAPP_REG_8BIT:
*val = data[0];
break;
default:
@@ -165,31 +165,28 @@ static int __smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val,
bool only8)
{
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- unsigned int len = (u8)(reg >> 16);
+ u8 len = SMIAPP_REG_WIDTH(reg);
int rval;
- if (len != SMIA_REG_8BIT && len != SMIA_REG_16BIT
- && len != SMIA_REG_32BIT)
+ if (len != SMIAPP_REG_8BIT && len != SMIAPP_REG_16BIT
+ && len != SMIAPP_REG_32BIT)
return -EINVAL;
- if (smiapp_quirk_reg(sensor, reg, val))
- goto found_quirk;
-
- if (len == SMIA_REG_8BIT && !only8)
- rval = ____smiapp_read(sensor, (u16)reg, len, val);
+ if (len == SMIAPP_REG_8BIT || !only8)
+ rval = ____smiapp_read(sensor, SMIAPP_REG_ADDR(reg), len, val);
else
- rval = ____smiapp_read_8only(sensor, (u16)reg, len, val);
+ rval = ____smiapp_read_8only(sensor, SMIAPP_REG_ADDR(reg), len,
+ val);
if (rval < 0)
return rval;
-found_quirk:
- if (reg & SMIA_REG_FLAG_FLOAT)
+ if (reg & SMIAPP_REG_FLAG_FLOAT)
*val = float_to_u32_mul_1000000(client, *val);
return 0;
}
-int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val)
+int smiapp_read_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 *val)
{
return __smiapp_read(
sensor, reg, val,
@@ -197,28 +194,47 @@ int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val)
SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY));
}
+int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val)
+{
+ int rval;
+
+ *val = 0;
+ rval = smiapp_call_quirk(sensor, reg_access, false, &reg, val);
+ if (rval == -ENOIOCTLCMD)
+ return 0;
+ if (rval < 0)
+ return rval;
+
+ return smiapp_read_no_quirk(sensor, reg, val);
+}
+
int smiapp_read_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val)
{
+ int rval;
+
+ *val = 0;
+ rval = smiapp_call_quirk(sensor, reg_access, false, &reg, val);
+ if (rval == -ENOIOCTLCMD)
+ return 0;
+ if (rval < 0)
+ return rval;
+
return __smiapp_read(sensor, reg, val, true);
}
-/*
- * Write to a 8/16-bit register.
- * Returns zero if successful, or non-zero otherwise.
- */
-int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val)
+int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val)
{
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
struct i2c_msg msg;
unsigned char data[6];
unsigned int retries;
- unsigned int flags = reg >> 24;
- unsigned int len = (u8)(reg >> 16);
- u16 offset = reg;
+ u8 flags = SMIAPP_REG_FLAGS(reg);
+ u8 len = SMIAPP_REG_WIDTH(reg);
+ u16 offset = SMIAPP_REG_ADDR(reg);
int r;
- if ((len != SMIA_REG_8BIT && len != SMIA_REG_16BIT &&
- len != SMIA_REG_32BIT) || flags)
+ if ((len != SMIAPP_REG_8BIT && len != SMIAPP_REG_16BIT &&
+ len != SMIAPP_REG_32BIT) || flags)
return -EINVAL;
msg.addr = client->addr;
@@ -231,14 +247,14 @@ int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val)
data[1] = (u8) (reg & 0xff);
switch (len) {
- case SMIA_REG_8BIT:
+ case SMIAPP_REG_8BIT:
data[2] = val;
break;
- case SMIA_REG_16BIT:
+ case SMIAPP_REG_16BIT:
data[2] = val >> 8;
data[3] = val;
break;
- case SMIA_REG_32BIT:
+ case SMIAPP_REG_32BIT:
data[2] = val >> 24;
data[3] = val >> 16;
data[4] = val >> 8;
@@ -271,3 +287,20 @@ int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val)
return r;
}
+
+/*
+ * Write to a 8/16-bit register.
+ * Returns zero if successful, or non-zero otherwise.
+ */
+int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val)
+{
+ int rval;
+
+ rval = smiapp_call_quirk(sensor, reg_access, true, &reg, &val);
+ if (rval == -ENOIOCTLCMD)
+ return 0;
+ if (rval < 0)
+ return rval;
+
+ return smiapp_write_no_quirk(sensor, reg, val);
+}
diff --git a/drivers/media/i2c/smiapp/smiapp-regs.h b/drivers/media/i2c/smiapp/smiapp-regs.h
index eefc6c84d5fe..35521125a2cc 100644
--- a/drivers/media/i2c/smiapp/smiapp-regs.h
+++ b/drivers/media/i2c/smiapp/smiapp-regs.h
@@ -28,22 +28,23 @@
#include <linux/i2c.h>
#include <linux/types.h>
+#define SMIAPP_REG_ADDR(reg) ((u16)reg)
+#define SMIAPP_REG_WIDTH(reg) ((u8)(reg >> 16))
+#define SMIAPP_REG_FLAGS(reg) ((u8)(reg >> 24))
+
/* Use upper 8 bits of the type field for flags */
-#define SMIA_REG_FLAG_FLOAT (1 << 24)
+#define SMIAPP_REG_FLAG_FLOAT (1 << 24)
-#define SMIA_REG_8BIT 1
-#define SMIA_REG_16BIT 2
-#define SMIA_REG_32BIT 4
-struct smia_reg {
- u16 type;
- u16 reg; /* 16-bit offset */
- u32 val; /* 8/16/32-bit value */
-};
+#define SMIAPP_REG_8BIT 1
+#define SMIAPP_REG_16BIT 2
+#define SMIAPP_REG_32BIT 4
struct smiapp_sensor;
+int smiapp_read_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 *val);
int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val);
int smiapp_read_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val);
+int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val);
int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val);
#endif
diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c
index ab54628d9411..416402eb4f82 100644
--- a/drivers/media/i2c/soc_camera/tw9910.c
+++ b/drivers/media/i2c/soc_camera/tw9910.c
@@ -814,8 +814,6 @@ done:
}
static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
- .s_std = tw9910_s_std,
- .g_std = tw9910_g_std,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = tw9910_g_register,
.s_register = tw9910_s_register,
@@ -872,7 +870,15 @@ static int tw9910_s_mbus_config(struct v4l2_subdev *sd,
return i2c_smbus_write_byte_data(client, OUTCTR1, val);
}
+static int tw9910_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm)
+{
+ *norm = V4L2_STD_NTSC | V4L2_STD_PAL;
+ return 0;
+}
+
static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = {
+ .s_std = tw9910_s_std,
+ .g_std = tw9910_g_std,
.s_stream = tw9910_s_stream,
.g_mbus_fmt = tw9910_g_fmt,
.s_mbus_fmt = tw9910_s_fmt,
@@ -882,6 +888,7 @@ static struct v4l2_subdev_video_ops tw9910_subdev_video_ops = {
.enum_mbus_fmt = tw9910_enum_fmt,
.g_mbus_config = tw9910_g_mbus_config,
.s_mbus_config = tw9910_s_mbus_config,
+ .g_tvnorms = tw9910_g_tvnorms,
};
static struct v4l2_subdev_ops tw9910_subdev_ops = {
diff --git a/drivers/media/i2c/sony-btf-mpx.c b/drivers/media/i2c/sony-btf-mpx.c
index 32d82320b485..1da8004f5a8e 100644
--- a/drivers/media/i2c/sony-btf-mpx.c
+++ b/drivers/media/i2c/sony-btf-mpx.c
@@ -327,18 +327,18 @@ static int sony_btf_mpx_s_tuner(struct v4l2_subdev *sd, const struct v4l2_tuner
/* --------------------------------------------------------------------------*/
-static const struct v4l2_subdev_core_ops sony_btf_mpx_core_ops = {
- .s_std = sony_btf_mpx_s_std,
-};
-
static const struct v4l2_subdev_tuner_ops sony_btf_mpx_tuner_ops = {
.s_tuner = sony_btf_mpx_s_tuner,
.g_tuner = sony_btf_mpx_g_tuner,
};
+static const struct v4l2_subdev_video_ops sony_btf_mpx_video_ops = {
+ .s_std = sony_btf_mpx_s_std,
+};
+
static const struct v4l2_subdev_ops sony_btf_mpx_ops = {
- .core = &sony_btf_mpx_core_ops,
.tuner = &sony_btf_mpx_tuner_ops,
+ .video = &sony_btf_mpx_video_ops,
};
/* --------------------------------------------------------------------------*/
diff --git a/drivers/media/i2c/ths8200.c b/drivers/media/i2c/ths8200.c
index f72561e79739..656d889c1c79 100644
--- a/drivers/media/i2c/ths8200.c
+++ b/drivers/media/i2c/ths8200.c
@@ -410,6 +410,9 @@ static int ths8200_g_dv_timings(struct v4l2_subdev *sd,
static int ths8200_enum_dv_timings(struct v4l2_subdev *sd,
struct v4l2_enum_dv_timings *timings)
{
+ if (timings->pad != 0)
+ return -EINVAL;
+
return v4l2_enum_dv_timings_cap(timings, &ths8200_timings_cap,
NULL, NULL);
}
@@ -417,6 +420,9 @@ static int ths8200_enum_dv_timings(struct v4l2_subdev *sd,
static int ths8200_dv_timings_cap(struct v4l2_subdev *sd,
struct v4l2_dv_timings_cap *cap)
{
+ if (cap->pad != 0)
+ return -EINVAL;
+
*cap = ths8200_timings_cap;
return 0;
}
@@ -426,6 +432,9 @@ static const struct v4l2_subdev_video_ops ths8200_video_ops = {
.s_stream = ths8200_s_stream,
.s_dv_timings = ths8200_s_dv_timings,
.g_dv_timings = ths8200_g_dv_timings,
+};
+
+static const struct v4l2_subdev_pad_ops ths8200_pad_ops = {
.enum_dv_timings = ths8200_enum_dv_timings,
.dv_timings_cap = ths8200_dv_timings_cap,
};
@@ -434,6 +443,7 @@ static const struct v4l2_subdev_video_ops ths8200_video_ops = {
static const struct v4l2_subdev_ops ths8200_ops = {
.core = &ths8200_core_ops,
.video = &ths8200_video_ops,
+ .pad = &ths8200_pad_ops,
};
static int ths8200_probe(struct i2c_client *client,
diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c
index d76c53a8f027..070c152da95a 100644
--- a/drivers/media/i2c/tvaudio.c
+++ b/drivers/media/i2c/tvaudio.c
@@ -1862,7 +1862,6 @@ static const struct v4l2_subdev_core_ops tvaudio_core_ops = {
.s_ctrl = v4l2_subdev_s_ctrl,
.queryctrl = v4l2_subdev_queryctrl,
.querymenu = v4l2_subdev_querymenu,
- .s_std = tvaudio_s_std,
};
static const struct v4l2_subdev_tuner_ops tvaudio_tuner_ops = {
@@ -1876,10 +1875,15 @@ static const struct v4l2_subdev_audio_ops tvaudio_audio_ops = {
.s_routing = tvaudio_s_routing,
};
+static const struct v4l2_subdev_video_ops tvaudio_video_ops = {
+ .s_std = tvaudio_s_std,
+};
+
static const struct v4l2_subdev_ops tvaudio_ops = {
.core = &tvaudio_core_ops,
.tuner = &tvaudio_tuner_ops,
.audio = &tvaudio_audio_ops,
+ .video = &tvaudio_video_ops,
};
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index ca001178c5bf..b9dabc9f4050 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -1010,10 +1010,10 @@ static const struct v4l2_subdev_core_ops tvp514x_core_ops = {
.s_ctrl = v4l2_subdev_s_ctrl,
.queryctrl = v4l2_subdev_queryctrl,
.querymenu = v4l2_subdev_querymenu,
- .s_std = tvp514x_s_std,
};
static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
+ .s_std = tvp514x_s_std,
.s_routing = tvp514x_s_routing,
.querystd = tvp514x_querystd,
.enum_mbus_fmt = tvp514x_enum_mbus_fmt,
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 4fd3688e1164..a9121254e37a 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -913,7 +913,7 @@ static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
static int tvp5150_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
+ struct tvp5150 *decoder = to_tvp5150(sd);
a->c = decoder->rect;
a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -923,7 +923,7 @@ static int tvp5150_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
static int tvp5150_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
{
- struct tvp5150 *decoder = container_of(sd, struct tvp5150, sd);
+ struct tvp5150 *decoder = to_tvp5150(sd);
v4l2_std_id std;
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -1063,7 +1063,6 @@ static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
.log_status = tvp5150_log_status,
- .s_std = tvp5150_s_std,
.reset = tvp5150_reset,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = tvp5150_g_register,
@@ -1076,6 +1075,7 @@ static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
};
static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
+ .s_std = tvp5150_s_std,
.s_routing = tvp5150_s_routing,
.enum_mbus_fmt = tvp5150_enum_mbus_fmt,
.s_mbus_fmt = tvp5150_mbus_fmt,
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
index c4e1e2cb3094..11f2387e1dab 100644
--- a/drivers/media/i2c/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
@@ -833,6 +833,9 @@ static int tvp7002_log_status(struct v4l2_subdev *sd)
static int tvp7002_enum_dv_timings(struct v4l2_subdev *sd,
struct v4l2_enum_dv_timings *timings)
{
+ if (timings->pad != 0)
+ return -EINVAL;
+
/* Check requested format index is within range */
if (timings->index >= NUM_TIMINGS)
return -EINVAL;
@@ -924,7 +927,6 @@ static const struct v4l2_subdev_core_ops tvp7002_core_ops = {
static const struct v4l2_subdev_video_ops tvp7002_video_ops = {
.g_dv_timings = tvp7002_g_dv_timings,
.s_dv_timings = tvp7002_s_dv_timings,
- .enum_dv_timings = tvp7002_enum_dv_timings,
.query_dv_timings = tvp7002_query_dv_timings,
.s_stream = tvp7002_s_stream,
.g_mbus_fmt = tvp7002_mbus_fmt,
@@ -938,6 +940,7 @@ static const struct v4l2_subdev_pad_ops tvp7002_pad_ops = {
.enum_mbus_code = tvp7002_enum_mbus_code,
.get_fmt = tvp7002_get_pad_format,
.set_fmt = tvp7002_set_pad_format,
+ .enum_dv_timings = tvp7002_enum_dv_timings,
};
/* V4L2 top level operation handlers */
diff --git a/drivers/media/i2c/tw2804.c b/drivers/media/i2c/tw2804.c
index f58607df6193..7347480c0b0c 100644
--- a/drivers/media/i2c/tw2804.c
+++ b/drivers/media/i2c/tw2804.c
@@ -342,12 +342,12 @@ static const struct v4l2_ctrl_ops tw2804_ctrl_ops = {
};
static const struct v4l2_subdev_video_ops tw2804_video_ops = {
+ .s_std = tw2804_s_std,
.s_routing = tw2804_s_video_routing,
};
static const struct v4l2_subdev_core_ops tw2804_core_ops = {
.log_status = tw2804_log_status,
- .s_std = tw2804_s_std,
};
static const struct v4l2_subdev_ops tw2804_ops = {
diff --git a/drivers/media/i2c/tw9903.c b/drivers/media/i2c/tw9903.c
index 285b759a5f7f..12c7d211a4a4 100644
--- a/drivers/media/i2c/tw9903.c
+++ b/drivers/media/i2c/tw9903.c
@@ -187,10 +187,10 @@ static const struct v4l2_ctrl_ops tw9903_ctrl_ops = {
static const struct v4l2_subdev_core_ops tw9903_core_ops = {
.log_status = tw9903_log_status,
- .s_std = tw9903_s_std,
};
static const struct v4l2_subdev_video_ops tw9903_video_ops = {
+ .s_std = tw9903_s_std,
.s_routing = tw9903_s_video_routing,
};
diff --git a/drivers/media/i2c/tw9906.c b/drivers/media/i2c/tw9906.c
index f6bef25bd9ce..2672d89265ff 100644
--- a/drivers/media/i2c/tw9906.c
+++ b/drivers/media/i2c/tw9906.c
@@ -157,10 +157,10 @@ static const struct v4l2_ctrl_ops tw9906_ctrl_ops = {
static const struct v4l2_subdev_core_ops tw9906_core_ops = {
.log_status = tw9906_log_status,
- .s_std = tw9906_s_std,
};
static const struct v4l2_subdev_video_ops tw9906_video_ops = {
+ .s_std = tw9906_s_std,
.s_routing = tw9906_s_video_routing,
};
diff --git a/drivers/media/i2c/vp27smpx.c b/drivers/media/i2c/vp27smpx.c
index 6a3a3ff7ee6a..819ab6d12989 100644
--- a/drivers/media/i2c/vp27smpx.c
+++ b/drivers/media/i2c/vp27smpx.c
@@ -124,7 +124,6 @@ static int vp27smpx_log_status(struct v4l2_subdev *sd)
static const struct v4l2_subdev_core_ops vp27smpx_core_ops = {
.log_status = vp27smpx_log_status,
- .s_std = vp27smpx_s_std,
};
static const struct v4l2_subdev_tuner_ops vp27smpx_tuner_ops = {
@@ -133,9 +132,14 @@ static const struct v4l2_subdev_tuner_ops vp27smpx_tuner_ops = {
.g_tuner = vp27smpx_g_tuner,
};
+static const struct v4l2_subdev_video_ops vp27smpx_video_ops = {
+ .s_std = vp27smpx_s_std,
+};
+
static const struct v4l2_subdev_ops vp27smpx_ops = {
.core = &vp27smpx_core_ops,
.tuner = &vp27smpx_tuner_ops,
+ .video = &vp27smpx_video_ops,
};
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/i2c/vpx3220.c b/drivers/media/i2c/vpx3220.c
index ece90df6a043..016e766e72ba 100644
--- a/drivers/media/i2c/vpx3220.c
+++ b/drivers/media/i2c/vpx3220.c
@@ -457,10 +457,10 @@ static const struct v4l2_subdev_core_ops vpx3220_core_ops = {
.s_ctrl = v4l2_subdev_s_ctrl,
.queryctrl = v4l2_subdev_queryctrl,
.querymenu = v4l2_subdev_querymenu,
- .s_std = vpx3220_s_std,
};
static const struct v4l2_subdev_video_ops vpx3220_video_ops = {
+ .s_std = vpx3220_s_std,
.s_routing = vpx3220_s_routing,
.s_stream = vpx3220_s_stream,
.querystd = vpx3220_querystd,
diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c
index 703560fa5e73..88b97c9e64ac 100644
--- a/drivers/media/media-device.c
+++ b/drivers/media/media-device.c
@@ -373,7 +373,8 @@ static void media_device_release(struct media_devnode *mdev)
* - dev must point to the parent device
* - model must be filled with the device model name
*/
-int __must_check media_device_register(struct media_device *mdev)
+int __must_check __media_device_register(struct media_device *mdev,
+ struct module *owner)
{
int ret;
@@ -389,7 +390,7 @@ int __must_check media_device_register(struct media_device *mdev)
mdev->devnode.fops = &media_device_fops;
mdev->devnode.parent = mdev->dev;
mdev->devnode.release = media_device_release;
- ret = media_devnode_register(&mdev->devnode);
+ ret = media_devnode_register(&mdev->devnode, owner);
if (ret < 0)
return ret;
@@ -401,7 +402,7 @@ int __must_check media_device_register(struct media_device *mdev)
return 0;
}
-EXPORT_SYMBOL_GPL(media_device_register);
+EXPORT_SYMBOL_GPL(__media_device_register);
/**
* media_device_unregister - unregister a media device
diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c
index fb0f0469fad7..7acd19c881de 100644
--- a/drivers/media/media-devnode.c
+++ b/drivers/media/media-devnode.c
@@ -232,7 +232,8 @@ static const struct file_operations media_devnode_fops = {
* the media_devnode structure is *not* called, so the caller is responsible for
* freeing any data.
*/
-int __must_check media_devnode_register(struct media_devnode *mdev)
+int __must_check media_devnode_register(struct media_devnode *mdev,
+ struct module *owner)
{
int minor;
int ret;
@@ -253,7 +254,7 @@ int __must_check media_devnode_register(struct media_devnode *mdev)
/* Part 2: Initialize and register the character device */
cdev_init(&mdev->cdev, &media_devnode_fops);
- mdev->cdev.owner = mdev->fops->owner;
+ mdev->cdev.owner = owner;
ret = cdev_add(&mdev->cdev, MKDEV(MAJOR(media_dev_t), mdev->minor), 1);
if (ret < 0) {
diff --git a/drivers/media/parport/bw-qcam.c b/drivers/media/parport/bw-qcam.c
index 8a0e84c7d495..416507a83668 100644
--- a/drivers/media/parport/bw-qcam.c
+++ b/drivers/media/parport/bw-qcam.c
@@ -937,7 +937,7 @@ static struct qcam *qcam_init(struct parport *port)
return NULL;
v4l2_dev = &qcam->v4l2_dev;
- snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "bw-qcam%d", num_cams);
+ snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "bw-qcam%u", num_cams);
if (v4l2_device_register(port->dev, v4l2_dev) < 0) {
v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c
index d06963b3dcf3..d8ec583c154c 100644
--- a/drivers/media/pci/bt8xx/bttv-cards.c
+++ b/drivers/media/pci/bt8xx/bttv-cards.c
@@ -52,6 +52,7 @@ static void osprey_eeprom(struct bttv *btv, const u8 ee[256]);
static void modtec_eeprom(struct bttv *btv);
static void init_PXC200(struct bttv *btv);
static void init_RTV24(struct bttv *btv);
+static void init_PCI8604PW(struct bttv *btv);
static void rv605_muxsel(struct bttv *btv, unsigned int input);
static void eagle_muxsel(struct bttv *btv, unsigned int input);
@@ -2871,6 +2872,22 @@ struct tvcard bttv_tvcards[] = {
.has_remote = 1,
.has_radio = 1,
},
+ /* ---- card 0xa6---------------------------------- */
+ [BTTV_BOARD_PCI_8604PW] = {
+ /* PCI-8604PW with special unlock sequence */
+ .name = "PCI-8604PW",
+ .video_inputs = 2,
+ /* .audio_inputs= 0, */
+ .svhs = NO_SVHS,
+ /* The second input is available on CN4, if populated.
+ * The other 5x2 header (CN2?) connects to the same inputs
+ * as the on-board BNCs */
+ .muxsel = MUXSEL(2, 3),
+ .tuner_type = TUNER_ABSENT,
+ .no_msp34xx = 1,
+ .no_tda7432 = 1,
+ .pll = PLL_35,
+ },
};
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3305,6 +3322,9 @@ void bttv_init_card1(struct bttv *btv)
case BTTV_BOARD_ADLINK_RTV24:
init_RTV24( btv );
break;
+ case BTTV_BOARD_PCI_8604PW:
+ init_PCI8604PW(btv);
+ break;
}
if (!bttv_tvcards[btv->c.type].has_dvb)
@@ -4185,6 +4205,96 @@ init_RTV24 (struct bttv *btv)
/* ----------------------------------------------------------------------- */
+/*
+ * The PCI-8604PW contains a CPLD, probably an ispMACH 4A, that filters
+ * the PCI REQ signals comming from the four BT878 chips. After power
+ * up, the CPLD does not forward requests to the bus, which prevents
+ * the BT878 from fetching RISC instructions from memory. While the
+ * CPLD is connected to most of the GPIOs of PCI device 0xD, only
+ * five appear to play a role in unlocking the REQ signal. The following
+ * sequence has been determined by trial and error without access to the
+ * original driver.
+ *
+ * Eight GPIOs of device 0xC are provided on connector CN4 (4 in, 4 out).
+ * Devices 0xE and 0xF do not appear to have anything connected to their
+ * GPIOs.
+ *
+ * The correct GPIO_OUT_EN value might have some more bits set. It should
+ * be possible to derive it from a boundary scan of the CPLD. Its JTAG
+ * pins are routed to test points.
+ *
+ */
+/* ----------------------------------------------------------------------- */
+static void
+init_PCI8604PW(struct bttv *btv)
+{
+ int state;
+
+ if ((PCI_SLOT(btv->c.pci->devfn) & ~3) != 0xC) {
+ pr_warn("This is not a PCI-8604PW\n");
+ return;
+ }
+
+ if (PCI_SLOT(btv->c.pci->devfn) != 0xD)
+ return;
+
+ btwrite(0x080002, BT848_GPIO_OUT_EN);
+
+ state = (btread(BT848_GPIO_DATA) >> 21) & 7;
+
+ for (;;) {
+ switch (state) {
+ case 1:
+ case 5:
+ case 6:
+ case 4:
+ pr_debug("PCI-8604PW in state %i, toggling pin\n",
+ state);
+ btwrite(0x080000, BT848_GPIO_DATA);
+ msleep(1);
+ btwrite(0x000000, BT848_GPIO_DATA);
+ msleep(1);
+ break;
+ case 7:
+ pr_info("PCI-8604PW unlocked\n");
+ return;
+ case 0:
+ /* FIXME: If we are in state 7 and toggle GPIO[19] one
+ more time, the CPLD goes into state 0, where PCI bus
+ mastering is inhibited again. We have not managed to
+ get out of that state. */
+
+ pr_err("PCI-8604PW locked until reset\n");
+ return;
+ default:
+ pr_err("PCI-8604PW in unknown state %i\n", state);
+ return;
+ }
+
+ state = (state << 4) | ((btread(BT848_GPIO_DATA) >> 21) & 7);
+
+ switch (state) {
+ case 0x15:
+ case 0x56:
+ case 0x64:
+ case 0x47:
+ /* The transition from state 7 to state 0 is, as explained
+ above, valid but undesired and with this code impossible
+ as we exit as soon as we are in state 7.
+ case 0x70: */
+ break;
+ default:
+ pr_err("PCI-8604PW invalid transition %i -> %i\n",
+ state >> 4, state & 7);
+ return;
+ }
+ state &= 7;
+ }
+}
+
+
+
+/* ----------------------------------------------------------------------- */
/* Miro Pro radio stuff -- the tea5757 is connected to some GPIO ports */
/*
* Copyright (c) 1999 Csaba Halasz <qgehali@uni-miskolc.hu>
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index afcd53bfcf8e..da780f42b121 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -1182,7 +1182,7 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
break;
}
id = tvnorm->v4l2_id;
- bttv_call_all(btv, core, s_std, id);
+ bttv_call_all(btv, video, s_std, id);
return 0;
}
diff --git a/drivers/media/pci/bt8xx/bttv.h b/drivers/media/pci/bt8xx/bttv.h
index bb5da349a46e..f08126244662 100644
--- a/drivers/media/pci/bt8xx/bttv.h
+++ b/drivers/media/pci/bt8xx/bttv.h
@@ -189,6 +189,7 @@
#define BTTV_BOARD_BT848_CAP_14 0xa3
#define BTTV_BOARD_CYBERVISION_CV06 0xa4
#define BTTV_BOARD_KWORLD_VSTREAM_XPERT 0xa5
+#define BTTV_BOARD_PCI_8604PW 0xa6
/* more card-specific defines */
#define PT2254_L_CHANNEL 0x10
diff --git a/drivers/media/pci/bt8xx/dst.c b/drivers/media/pci/bt8xx/dst.c
index 430b3eb11815..f2261dfe5d1a 100644
--- a/drivers/media/pci/bt8xx/dst.c
+++ b/drivers/media/pci/bt8xx/dst.c
@@ -1544,7 +1544,7 @@ static int dst_send_burst(struct dvb_frontend *fe, fe_sec_mini_cmd_t minicmd)
}
-static int dst_init(struct dvb_frontend *fe)
+static int bt8xx_dst_init(struct dvb_frontend *fe)
{
struct dst_state *state = fe->demodulator_priv;
@@ -1707,7 +1707,7 @@ static int dst_get_frontend(struct dvb_frontend *fe)
return 0;
}
-static void dst_release(struct dvb_frontend *fe)
+static void bt8xx_dst_release(struct dvb_frontend *fe)
{
struct dst_state *state = fe->demodulator_priv;
if (state->dst_ca) {
@@ -1776,8 +1776,8 @@ static struct dvb_frontend_ops dst_dvbt_ops = {
FE_CAN_GUARD_INTERVAL_AUTO
},
- .release = dst_release,
- .init = dst_init,
+ .release = bt8xx_dst_release,
+ .init = bt8xx_dst_init,
.tune = dst_tune_frontend,
.set_frontend = dst_set_frontend,
.get_frontend = dst_get_frontend,
@@ -1801,8 +1801,8 @@ static struct dvb_frontend_ops dst_dvbs_ops = {
.caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK
},
- .release = dst_release,
- .init = dst_init,
+ .release = bt8xx_dst_release,
+ .init = bt8xx_dst_init,
.tune = dst_tune_frontend,
.set_frontend = dst_set_frontend,
.get_frontend = dst_get_frontend,
@@ -1834,8 +1834,8 @@ static struct dvb_frontend_ops dst_dvbc_ops = {
FE_CAN_QAM_256
},
- .release = dst_release,
- .init = dst_init,
+ .release = bt8xx_dst_release,
+ .init = bt8xx_dst_init,
.tune = dst_tune_frontend,
.set_frontend = dst_set_frontend,
.get_frontend = dst_get_frontend,
@@ -1857,8 +1857,8 @@ static struct dvb_frontend_ops dst_atsc_ops = {
.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
},
- .release = dst_release,
- .init = dst_init,
+ .release = bt8xx_dst_release,
+ .init = bt8xx_dst_init,
.tune = dst_tune_frontend,
.set_frontend = dst_set_frontend,
.get_frontend = dst_get_frontend,
diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c
index c4890a430dc6..2d3afe0431a9 100644
--- a/drivers/media/pci/cx18/cx18-av-core.c
+++ b/drivers/media/pci/cx18/cx18-av-core.c
@@ -1263,7 +1263,6 @@ static const struct v4l2_subdev_core_ops cx18_av_general_ops = {
.log_status = cx18_av_log_status,
.load_fw = cx18_av_load_fw,
.reset = cx18_av_reset,
- .s_std = cx18_av_s_std,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = cx18_av_g_register,
.s_register = cx18_av_s_register,
@@ -1283,6 +1282,7 @@ static const struct v4l2_subdev_audio_ops cx18_av_audio_ops = {
};
static const struct v4l2_subdev_video_ops cx18_av_video_ops = {
+ .s_std = cx18_av_s_std,
.s_routing = cx18_av_s_video_routing,
.s_stream = cx18_av_s_stream,
.s_mbus_fmt = cx18_av_s_mbus_fmt,
diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c
index 4bfd865a4106..76a3b4ac541e 100644
--- a/drivers/media/pci/cx18/cx18-fileops.c
+++ b/drivers/media/pci/cx18/cx18-fileops.c
@@ -760,7 +760,7 @@ int cx18_v4l2_close(struct file *filp)
/* Mark that the radio is no longer in use */
clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags);
/* Switch tuner to TV */
- cx18_call_all(cx, core, s_std, cx->std);
+ cx18_call_all(cx, video, s_std, cx->std);
/* Select correct audio input (i.e. TV tuner or Line in) */
cx18_audio_set_io(cx);
if (atomic_read(&cx->ana_capturing) > 0) {
diff --git a/drivers/media/pci/cx18/cx18-gpio.c b/drivers/media/pci/cx18/cx18-gpio.c
index 5374aeb0cd22..38dc6b8f8254 100644
--- a/drivers/media/pci/cx18/cx18-gpio.c
+++ b/drivers/media/pci/cx18/cx18-gpio.c
@@ -180,7 +180,6 @@ static int gpiomux_s_audio_routing(struct v4l2_subdev *sd,
static const struct v4l2_subdev_core_ops gpiomux_core_ops = {
.log_status = gpiomux_log_status,
- .s_std = gpiomux_s_std,
};
static const struct v4l2_subdev_tuner_ops gpiomux_tuner_ops = {
@@ -191,10 +190,15 @@ static const struct v4l2_subdev_audio_ops gpiomux_audio_ops = {
.s_routing = gpiomux_s_audio_routing,
};
+static const struct v4l2_subdev_video_ops gpiomux_video_ops = {
+ .s_std = gpiomux_s_std,
+};
+
static const struct v4l2_subdev_ops gpiomux_ops = {
.core = &gpiomux_core_ops,
.tuner = &gpiomux_tuner_ops,
.audio = &gpiomux_audio_ops,
+ .video = &gpiomux_video_ops,
};
/*
diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c
index 1110bcb14e2f..fefb2cd35838 100644
--- a/drivers/media/pci/cx18/cx18-ioctl.c
+++ b/drivers/media/pci/cx18/cx18-ioctl.c
@@ -602,7 +602,7 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id std)
(unsigned long long) cx->std);
/* Tuner */
- cx18_call_all(cx, core, s_std, cx->std);
+ cx18_call_all(cx, video, s_std, cx->std);
return 0;
}
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index 7891f34157d1..e0a59523cf3c 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -326,7 +326,7 @@ int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
dev->tvnorm = norm;
- call_all(dev, core, s_std, norm);
+ call_all(dev, video, s_std, norm);
return 0;
}
@@ -1589,7 +1589,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev,
fe = &dev->ts1.analog_fe;
if (fe && fe->ops.tuner_ops.set_analog_params) {
- call_all(dev, core, s_std, dev->tvnorm);
+ call_all(dev, video, s_std, dev->tvnorm);
fe->ops.tuner_ops.set_analog_params(fe, &params);
}
else
diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c
index ad59dc9235ae..e061c88b697e 100644
--- a/drivers/media/pci/cx88/cx88-core.c
+++ b/drivers/media/pci/cx88/cx88-core.c
@@ -1012,7 +1012,7 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
set_tvaudio(core);
// tell i2c chips
- call_all(core, core, s_std, norm);
+ call_all(core, video, s_std, norm);
/* The chroma_agc control should be inaccessible if the video format is SECAM */
v4l2_ctrl_grab(core->chroma_agc, cxiformat == VideoFormatSECAM);
diff --git a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
index e1863dbf4edc..7a9b98bc208b 100644
--- a/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
+++ b/drivers/media/pci/ivtv/ivtv-alsa-pcm.c
@@ -159,6 +159,12 @@ static int snd_ivtv_pcm_capture_open(struct snd_pcm_substream *substream)
/* Instruct the CX2341[56] to start sending packets */
snd_ivtv_lock(itvsc);
+
+ if (ivtv_init_on_first_open(itv)) {
+ snd_ivtv_unlock(itvsc);
+ return -ENXIO;
+ }
+
s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM];
v4l2_fh_init(&item.fh, s->vdev);
diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c
index 9caffd8aa995..e5ff6277ca85 100644
--- a/drivers/media/pci/ivtv/ivtv-fileops.c
+++ b/drivers/media/pci/ivtv/ivtv-fileops.c
@@ -894,7 +894,7 @@ int ivtv_v4l2_close(struct file *filp)
/* Mark that the radio is no longer in use */
clear_bit(IVTV_F_I_RADIO_USER, &itv->i_flags);
/* Switch tuner to TV */
- ivtv_call_all(itv, core, s_std, itv->std);
+ ivtv_call_all(itv, video, s_std, itv->std);
/* Select correct audio input (i.e. TV tuner or Line in) */
ivtv_audio_set_io(itv);
if (itv->hw_flags & IVTV_HW_SAA711X) {
diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c
index 807b275a847e..b3667a00db3a 100644
--- a/drivers/media/pci/ivtv/ivtv-ioctl.c
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.c
@@ -1090,7 +1090,7 @@ void ivtv_s_std_enc(struct ivtv *itv, v4l2_std_id std)
itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284;
/* Tuner */
- ivtv_call_all(itv, core, s_std, itv->std);
+ ivtv_call_all(itv, video, s_std, itv->std);
}
void ivtv_s_std_dec(struct ivtv *itv, v4l2_std_id std)
diff --git a/drivers/media/pci/saa7134/Kconfig b/drivers/media/pci/saa7134/Kconfig
index 7883393571e5..18ae75546302 100644
--- a/drivers/media/pci/saa7134/Kconfig
+++ b/drivers/media/pci/saa7134/Kconfig
@@ -1,7 +1,7 @@
config VIDEO_SAA7134
tristate "Philips SAA7134 support"
depends on VIDEO_DEV && PCI && I2C
- select VIDEOBUF_DMA_SG
+ select VIDEOBUF2_DMA_SG
select VIDEO_TUNER
select VIDEO_TVEEPROM
select CRC32
@@ -37,7 +37,7 @@ config VIDEO_SAA7134_RC
config VIDEO_SAA7134_DVB
tristate "DVB/ATSC Support for saa7134 based TV cards"
depends on VIDEO_SAA7134 && DVB_CORE
- select VIDEOBUF_DVB
+ select VIDEOBUF2_DVB
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c
index e04a4d5d6672..40569894c1c9 100644
--- a/drivers/media/pci/saa7134/saa7134-alsa.c
+++ b/drivers/media/pci/saa7134/saa7134-alsa.c
@@ -27,6 +27,7 @@
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <linux/interrupt.h>
+#include <linux/vmalloc.h>
#include "saa7134.h"
#include "saa7134-reg.h"
@@ -274,6 +275,82 @@ static int snd_card_saa7134_capture_trigger(struct snd_pcm_substream * substream
return err;
}
+static int saa7134_alsa_dma_init(struct saa7134_dev *dev, int nr_pages)
+{
+ struct saa7134_dmasound *dma = &dev->dmasound;
+ struct page *pg;
+ int i;
+
+ dma->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
+ if (NULL == dma->vaddr) {
+ dprintk("vmalloc_32(%d pages) failed\n", nr_pages);
+ return -ENOMEM;
+ }
+
+ dprintk("vmalloc is at addr 0x%08lx, size=%d\n",
+ (unsigned long)dma->vaddr,
+ nr_pages << PAGE_SHIFT);
+
+ memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT);
+ dma->nr_pages = nr_pages;
+
+ dma->sglist = vzalloc(dma->nr_pages * sizeof(*dma->sglist));
+ if (NULL == dma->sglist)
+ goto vzalloc_err;
+
+ sg_init_table(dma->sglist, dma->nr_pages);
+ for (i = 0; i < dma->nr_pages; i++) {
+ pg = vmalloc_to_page(dma->vaddr + i * PAGE_SIZE);
+ if (NULL == pg)
+ goto vmalloc_to_page_err;
+ sg_set_page(&dma->sglist[i], pg, PAGE_SIZE, 0);
+ }
+ return 0;
+
+vmalloc_to_page_err:
+ vfree(dma->sglist);
+ dma->sglist = NULL;
+vzalloc_err:
+ vfree(dma->vaddr);
+ dma->vaddr = NULL;
+ return -ENOMEM;
+}
+
+static int saa7134_alsa_dma_map(struct saa7134_dev *dev)
+{
+ struct saa7134_dmasound *dma = &dev->dmasound;
+
+ dma->sglen = dma_map_sg(&dev->pci->dev, dma->sglist,
+ dma->nr_pages, PCI_DMA_FROMDEVICE);
+
+ if (0 == dma->sglen) {
+ pr_warn("%s: saa7134_alsa_map_sg failed\n", __func__);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static int saa7134_alsa_dma_unmap(struct saa7134_dev *dev)
+{
+ struct saa7134_dmasound *dma = &dev->dmasound;
+
+ if (!dma->sglen)
+ return 0;
+
+ dma_unmap_sg(&dev->pci->dev, dma->sglist, dma->sglen, PCI_DMA_FROMDEVICE);
+ dma->sglen = 0;
+ return 0;
+}
+
+static int saa7134_alsa_dma_free(struct saa7134_dmasound *dma)
+{
+ vfree(dma->sglist);
+ dma->sglist = NULL;
+ vfree(dma->vaddr);
+ dma->vaddr = NULL;
+ return 0;
+}
+
/*
* DMA buffer initialization
*
@@ -291,9 +368,8 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
BUG_ON(!dev->dmasound.bufsize);
- videobuf_dma_init(&dev->dmasound.dma);
- err = videobuf_dma_init_kernel(&dev->dmasound.dma, PCI_DMA_FROMDEVICE,
- (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
+ err = saa7134_alsa_dma_init(dev,
+ (dev->dmasound.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
if (0 != err)
return err;
return 0;
@@ -310,7 +386,7 @@ static int dsp_buffer_free(struct saa7134_dev *dev)
{
BUG_ON(!dev->dmasound.blksize);
- videobuf_dma_free(&dev->dmasound.dma);
+ saa7134_alsa_dma_free(&dev->dmasound);
dev->dmasound.blocks = 0;
dev->dmasound.blksize = 0;
@@ -632,7 +708,7 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
/* release the old buffer */
if (substream->runtime->dma_area) {
saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
- videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+ saa7134_alsa_dma_unmap(dev);
dsp_buffer_free(dev);
substream->runtime->dma_area = NULL;
}
@@ -648,21 +724,22 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
return err;
}
- if (0 != (err = videobuf_dma_map(&dev->pci->dev, &dev->dmasound.dma))) {
+ err = saa7134_alsa_dma_map(dev);
+ if (err) {
dsp_buffer_free(dev);
return err;
}
- if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) {
- videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+ err = saa7134_pgtable_alloc(dev->pci, &dev->dmasound.pt);
+ if (err) {
+ saa7134_alsa_dma_unmap(dev);
dsp_buffer_free(dev);
return err;
}
- if (0 != (err = saa7134_pgtable_build(dev->pci,&dev->dmasound.pt,
- dev->dmasound.dma.sglist,
- dev->dmasound.dma.sglen,
- 0))) {
+ err = saa7134_pgtable_build(dev->pci, &dev->dmasound.pt,
+ dev->dmasound.sglist, dev->dmasound.sglen, 0);
+ if (err) {
saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
- videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+ saa7134_alsa_dma_unmap(dev);
dsp_buffer_free(dev);
return err;
}
@@ -671,7 +748,7 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
byte, but it doesn't work. So I allocate the DMA using the
V4L functions, and force ALSA to use that as the DMA area */
- substream->runtime->dma_area = dev->dmasound.dma.vaddr;
+ substream->runtime->dma_area = dev->dmasound.vaddr;
substream->runtime->dma_bytes = dev->dmasound.bufsize;
substream->runtime->dma_addr = 0;
@@ -698,7 +775,7 @@ static int snd_card_saa7134_hw_free(struct snd_pcm_substream * substream)
if (substream->runtime->dma_area) {
saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
- videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+ saa7134_alsa_dma_unmap(dev);
dsp_buffer_free(dev);
substream->runtime->dma_area = NULL;
}
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index 1362b4aab473..be19a051a492 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -69,6 +69,10 @@ module_param_named(no_overlay, saa7134_no_overlay, int, 0444);
MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)"
" [some VIA/SIS chipsets are known to have problem with overlay]");
+bool saa7134_userptr;
+module_param(saa7134_userptr, bool, 0644);
+MODULE_PARM_DESC(saa7134_userptr, "enable page-aligned userptr support");
+
static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
static unsigned int vbi_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
@@ -203,16 +207,16 @@ int saa7134_buffer_count(unsigned int size, unsigned int count)
int saa7134_buffer_startpage(struct saa7134_buf *buf)
{
- return saa7134_buffer_pages(buf->vb.bsize) * buf->vb.i;
+ return saa7134_buffer_pages(vb2_plane_size(&buf->vb2, 0)) * buf->vb2.v4l2_buf.index;
}
unsigned long saa7134_buffer_base(struct saa7134_buf *buf)
{
unsigned long base;
- struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+ struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
base = saa7134_buffer_startpage(buf) * 4096;
- base += dma->sglist[0].offset;
+ base += dma->sgl[0].offset;
return base;
}
@@ -237,14 +241,16 @@ int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
unsigned int startpage)
{
__le32 *ptr;
- unsigned int i,p;
+ unsigned int i, p;
BUG_ON(NULL == pt || NULL == pt->cpu);
ptr = pt->cpu + startpage;
- for (i = 0; i < length; i++, list++)
+ for (i = 0; i < length; i++, list = sg_next(list)) {
for (p = 0; p * 4096 < list->length; p++, ptr++)
- *ptr = cpu_to_le32(sg_dma_address(list) - list->offset);
+ *ptr = cpu_to_le32(sg_dma_address(list) +
+ list->offset + p * 4096);
+ }
return 0;
}
@@ -258,44 +264,31 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt)
/* ------------------------------------------------------------------ */
-void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
-{
- struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
- BUG_ON(in_interrupt());
-
- videobuf_waiton(q, &buf->vb, 0, 0);
- videobuf_dma_unmap(q->dev, dma);
- videobuf_dma_free(dma);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-/* ------------------------------------------------------------------ */
-
int saa7134_buffer_queue(struct saa7134_dev *dev,
struct saa7134_dmaqueue *q,
struct saa7134_buf *buf)
{
struct saa7134_buf *next = NULL;
+ unsigned long flags;
- assert_spin_locked(&dev->slock);
- dprintk("buffer_queue %p\n",buf);
+ spin_lock_irqsave(&dev->slock, flags);
+ dprintk("buffer_queue %p\n", buf);
if (NULL == q->curr) {
if (!q->need_two) {
q->curr = buf;
- buf->activate(dev,buf,NULL);
+ buf->activate(dev, buf, NULL);
} else if (list_empty(&q->queue)) {
- list_add_tail(&buf->vb.queue,&q->queue);
- buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->entry, &q->queue);
} else {
- next = list_entry(q->queue.next,struct saa7134_buf,
- vb.queue);
+ next = list_entry(q->queue.next, struct saa7134_buf,
+ entry);
q->curr = buf;
- buf->activate(dev,buf,next);
+ buf->activate(dev, buf, next);
}
} else {
- list_add_tail(&buf->vb.queue,&q->queue);
- buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->entry, &q->queue);
}
+ spin_unlock_irqrestore(&dev->slock, flags);
return 0;
}
@@ -303,13 +296,12 @@ void saa7134_buffer_finish(struct saa7134_dev *dev,
struct saa7134_dmaqueue *q,
unsigned int state)
{
- assert_spin_locked(&dev->slock);
- dprintk("buffer_finish %p\n",q->curr);
+ dprintk("buffer_finish %p\n", q->curr);
/* finish current buffer */
- q->curr->vb.state = state;
- v4l2_get_timestamp(&q->curr->vb.ts);
- wake_up(&q->curr->vb.done);
+ v4l2_get_timestamp(&q->curr->vb2.v4l2_buf.timestamp);
+ q->curr->vb2.v4l2_buf.sequence = q->seq_nr++;
+ vb2_buffer_done(&q->curr->vb2, state);
q->curr = NULL;
}
@@ -323,36 +315,31 @@ void saa7134_buffer_next(struct saa7134_dev *dev,
if (!list_empty(&q->queue)) {
/* activate next one from queue */
- buf = list_entry(q->queue.next,struct saa7134_buf,vb.queue);
+ buf = list_entry(q->queue.next, struct saa7134_buf, entry);
dprintk("buffer_next %p [prev=%p/next=%p]\n",
- buf,q->queue.prev,q->queue.next);
- list_del(&buf->vb.queue);
+ buf, q->queue.prev, q->queue.next);
+ list_del(&buf->entry);
if (!list_empty(&q->queue))
- next = list_entry(q->queue.next,struct saa7134_buf,
- vb.queue);
+ next = list_entry(q->queue.next, struct saa7134_buf, entry);
q->curr = buf;
- buf->activate(dev,buf,next);
+ buf->activate(dev, buf, next);
dprintk("buffer_next #2 prev=%p/next=%p\n",
- q->queue.prev,q->queue.next);
+ q->queue.prev, q->queue.next);
} else {
/* nothing to do -- just stop DMA */
- dprintk("buffer_next %p\n",NULL);
+ dprintk("buffer_next %p\n", NULL);
saa7134_set_dmabits(dev);
del_timer(&q->timeout);
-
- if (card_has_mpeg(dev))
- if (dev->ts_started)
- saa7134_ts_stop(dev);
}
}
void saa7134_buffer_timeout(unsigned long data)
{
- struct saa7134_dmaqueue *q = (struct saa7134_dmaqueue*)data;
+ struct saa7134_dmaqueue *q = (struct saa7134_dmaqueue *)data;
struct saa7134_dev *dev = q->dev;
unsigned long flags;
- spin_lock_irqsave(&dev->slock,flags);
+ spin_lock_irqsave(&dev->slock, flags);
/* try to reset the hardware (SWRST) */
saa_writeb(SAA7134_REGION_ENABLE, 0x00);
@@ -362,13 +349,33 @@ void saa7134_buffer_timeout(unsigned long data)
/* flag current buffer as failed,
try to start over with the next one. */
if (q->curr) {
- dprintk("timeout on %p\n",q->curr);
- saa7134_buffer_finish(dev,q,VIDEOBUF_ERROR);
+ dprintk("timeout on %p\n", q->curr);
+ saa7134_buffer_finish(dev, q, VB2_BUF_STATE_ERROR);
}
- saa7134_buffer_next(dev,q);
- spin_unlock_irqrestore(&dev->slock,flags);
+ saa7134_buffer_next(dev, q);
+ spin_unlock_irqrestore(&dev->slock, flags);
}
+void saa7134_stop_streaming(struct saa7134_dev *dev, struct saa7134_dmaqueue *q)
+{
+ unsigned long flags;
+ struct list_head *pos, *n;
+ struct saa7134_buf *tmp;
+
+ spin_lock_irqsave(&dev->slock, flags);
+ if (!list_empty(&q->queue)) {
+ list_for_each_safe(pos, n, &q->queue) {
+ tmp = list_entry(pos, struct saa7134_buf, entry);
+ vb2_buffer_done(&tmp->vb2, VB2_BUF_STATE_ERROR);
+ list_del(pos);
+ tmp = NULL;
+ }
+ }
+ spin_unlock_irqrestore(&dev->slock, flags);
+ saa7134_buffer_timeout((unsigned long)q); /* also calls del_timer(&q->timeout) */
+}
+EXPORT_SYMBOL_GPL(saa7134_stop_streaming);
+
/* ------------------------------------------------------------------ */
int saa7134_set_dmabits(struct saa7134_dev *dev)
@@ -388,12 +395,11 @@ int saa7134_set_dmabits(struct saa7134_dev *dev)
ctrl |= SAA7134_MAIN_CTRL_TE0;
irq |= SAA7134_IRQ1_INTE_RA0_1 |
SAA7134_IRQ1_INTE_RA0_0;
- cap = dev->video_q.curr->vb.field;
+ cap = dev->field;
}
/* video capture -- dma 1+2 (planar modes) */
- if (dev->video_q.curr &&
- dev->video_q.curr->fmt->planar) {
+ if (dev->video_q.curr && dev->fmt->planar) {
ctrl |= SAA7134_MAIN_CTRL_TE4 |
SAA7134_MAIN_CTRL_TE5;
}
@@ -1047,6 +1053,8 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
dev->video_dev = vdev_init(dev,&saa7134_video_template,"video");
dev->video_dev->ctrl_handler = &dev->ctrl_handler;
+ dev->video_dev->lock = &dev->lock;
+ dev->video_dev->queue = &dev->video_vbq;
err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
video_nr[dev->nr]);
if (err < 0) {
@@ -1059,6 +1067,8 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi");
dev->vbi_dev->ctrl_handler = &dev->ctrl_handler;
+ dev->vbi_dev->lock = &dev->lock;
+ dev->vbi_dev->queue = &dev->vbi_vbq;
err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
vbi_nr[dev->nr]);
@@ -1070,6 +1080,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
if (card_has_radio(dev)) {
dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio");
dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler;
+ dev->radio_dev->lock = &dev->lock;
err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
radio_nr[dev->nr]);
if (err < 0)
@@ -1189,7 +1200,7 @@ static int saa7134_buffer_requeue(struct saa7134_dev *dev,
if (!list_empty(&q->queue))
next = list_entry(q->queue.next, struct saa7134_buf,
- vb.queue);
+ entry);
buf->activate(dev, buf, next);
return 0;
@@ -1360,10 +1371,3 @@ EXPORT_SYMBOL(saa7134_pgtable_free);
EXPORT_SYMBOL(saa7134_pgtable_build);
EXPORT_SYMBOL(saa7134_pgtable_alloc);
EXPORT_SYMBOL(saa7134_set_dmabits);
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c
index 4a08ae31df2e..73ffbabf831c 100644
--- a/drivers/media/pci/saa7134/saa7134-dvb.c
+++ b/drivers/media/pci/saa7134/saa7134-dvb.c
@@ -602,10 +602,10 @@ static int configure_tda827x_fe(struct saa7134_dev *dev,
struct tda1004x_config *cdec_conf,
struct tda827x_config *tuner_conf)
{
- struct videobuf_dvb_frontend *fe0;
+ struct vb2_dvb_frontend *fe0;
/* Get the first frontend */
- fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+ fe0 = vb2_dvb_get_frontend(&dev->frontends, 1);
if (!fe0)
return -EINVAL;
@@ -1215,29 +1215,38 @@ static int dvb_init(struct saa7134_dev *dev)
{
int ret;
int attach_xc3028 = 0;
- struct videobuf_dvb_frontend *fe0;
+ struct vb2_dvb_frontend *fe0;
+ struct vb2_queue *q;
/* FIXME: add support for multi-frontend */
mutex_init(&dev->frontends.lock);
INIT_LIST_HEAD(&dev->frontends.felist);
printk(KERN_INFO "%s() allocating 1 frontend\n", __func__);
- fe0 = videobuf_dvb_alloc_frontend(&dev->frontends, 1);
+ fe0 = vb2_dvb_alloc_frontend(&dev->frontends, 1);
if (!fe0) {
printk(KERN_ERR "%s() failed to alloc\n", __func__);
return -ENOMEM;
}
- /* init struct videobuf_dvb */
+ /* init struct vb2_dvb */
dev->ts.nr_bufs = 32;
dev->ts.nr_packets = 32*4;
fe0->dvb.name = dev->name;
- videobuf_queue_sg_init(&fe0->dvb.dvbq, &saa7134_ts_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_ALTERNATE,
- sizeof(struct saa7134_buf),
- dev, NULL);
+ q = &fe0->dvb.dvbq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_READ;
+ q->drv_priv = &dev->ts_q;
+ q->ops = &saa7134_ts_qops;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->buf_struct_size = sizeof(struct saa7134_buf);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &dev->lock;
+ ret = vb2_queue_init(q);
+ if (ret) {
+ vb2_dvb_dealloc_frontends(&dev->frontends);
+ return ret;
+ }
switch (dev->board) {
case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
@@ -1876,7 +1885,7 @@ static int dvb_init(struct saa7134_dev *dev)
fe0->dvb.frontend->callback = saa7134_tuner_callback;
/* register everything else */
- ret = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
+ ret = vb2_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
&dev->pci->dev, adapter_nr, 0);
/* this sequence is necessary to make the tda1004x load its firmware
@@ -1893,16 +1902,17 @@ static int dvb_init(struct saa7134_dev *dev)
return ret;
detach_frontend:
- videobuf_dvb_dealloc_frontends(&dev->frontends);
+ vb2_dvb_dealloc_frontends(&dev->frontends);
+ vb2_queue_release(&fe0->dvb.dvbq);
return -EINVAL;
}
static int dvb_fini(struct saa7134_dev *dev)
{
- struct videobuf_dvb_frontend *fe0;
+ struct vb2_dvb_frontend *fe0;
/* Get the first frontend */
- fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+ fe0 = vb2_dvb_get_frontend(&dev->frontends, 1);
if (!fe0)
return -EINVAL;
@@ -1933,7 +1943,8 @@ static int dvb_fini(struct saa7134_dev *dev)
}
}
}
- videobuf_dvb_unregister_bus(&dev->frontends);
+ vb2_dvb_unregister_bus(&dev->frontends);
+ vb2_queue_release(&fe0->dvb.dvbq);
return 0;
}
@@ -1955,10 +1966,3 @@ static void __exit dvb_unregister(void)
module_init(dvb_register);
module_exit(dvb_unregister);
-
-/* ------------------------------------------------------------------ */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
index 0a9047e754b9..e65c760e4e8b 100644
--- a/drivers/media/pci/saa7134/saa7134-empress.c
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -48,21 +48,16 @@ MODULE_PARM_DESC(debug,"enable debug messages");
/* ------------------------------------------------------------------ */
-static void ts_reset_encoder(struct saa7134_dev* dev)
-{
- if (!dev->empress_started)
- return;
-
- saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
- msleep(10);
- saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
- msleep(100);
- dev->empress_started = 0;
-}
-
-static int ts_init_encoder(struct saa7134_dev* dev)
+static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
+ struct saa7134_dmaqueue *dmaq = vq->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
u32 leading_null_bytes = 0;
+ int err;
+
+ err = saa7134_ts_start_streaming(vq, count);
+ if (err)
+ return err;
/* If more cards start to need this, then this
should probably be added to the card definitions. */
@@ -73,97 +68,43 @@ static int ts_init_encoder(struct saa7134_dev* dev)
leading_null_bytes = 1;
break;
}
- ts_reset_encoder(dev);
saa_call_all(dev, core, init, leading_null_bytes);
- dev->empress_started = 1;
- return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int ts_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct saa7134_dev *dev = video_drvdata(file);
- struct saa7134_fh *fh;
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
-
- v4l2_fh_init(&fh->fh, vdev);
- file->private_data = fh;
- fh->is_empress = true;
- v4l2_fh_add(&fh->fh);
-
/* Unmute audio */
saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
- saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
-
- return 0;
-}
-
-static int ts_release(struct file *file)
-{
- struct saa7134_dev *dev = video_drvdata(file);
- struct saa7134_fh *fh = file->private_data;
-
- if (res_check(fh, RESOURCE_EMPRESS)) {
- videobuf_stop(&dev->empress_tsq);
- videobuf_mmap_free(&dev->empress_tsq);
-
- /* stop the encoder */
- ts_reset_encoder(dev);
-
- /* Mute audio */
- saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
- saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
- }
-
- v4l2_fh_del(&fh->fh);
- v4l2_fh_exit(&fh->fh);
+ saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
+ dev->empress_started = 1;
return 0;
}
-static ssize_t
-ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
+static void stop_streaming(struct vb2_queue *vq)
{
- struct saa7134_dev *dev = video_drvdata(file);
+ struct saa7134_dmaqueue *dmaq = vq->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
- if (res_locked(dev, RESOURCE_EMPRESS))
- return -EBUSY;
- if (!dev->empress_started)
- ts_init_encoder(dev);
-
- return videobuf_read_stream(&dev->empress_tsq,
- data, count, ppos, 0,
- file->f_flags & O_NONBLOCK);
-}
-
-static unsigned int
-ts_poll(struct file *file, struct poll_table_struct *wait)
-{
- unsigned long req_events = poll_requested_events(wait);
- struct saa7134_dev *dev = video_drvdata(file);
- struct saa7134_fh *fh = file->private_data;
- unsigned int rc = 0;
-
- if (v4l2_event_pending(&fh->fh))
- rc = POLLPRI;
- else if (req_events & POLLPRI)
- poll_wait(file, &fh->fh.wait, wait);
- return rc | videobuf_poll_stream(file, &dev->empress_tsq, wait);
+ saa7134_ts_stop_streaming(vq);
+ saa_writeb(SAA7134_SPECIAL_MODE, 0x00);
+ msleep(20);
+ saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
+ msleep(100);
+ /* Mute audio */
+ saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+ saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
+ dev->empress_started = 0;
}
+static struct vb2_ops saa7134_empress_qops = {
+ .queue_setup = saa7134_ts_queue_setup,
+ .buf_init = saa7134_ts_buffer_init,
+ .buf_prepare = saa7134_ts_buffer_prepare,
+ .buf_finish = saa7134_ts_buffer_finish,
+ .buf_queue = saa7134_vb2_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+};
-static int
-ts_mmap(struct file *file, struct vm_area_struct * vma)
-{
- struct saa7134_dev *dev = video_drvdata(file);
-
- return videobuf_mmap_mapper(&dev->empress_tsq, vma);
-}
+/* ------------------------------------------------------------------ */
static int empress_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
@@ -233,11 +174,11 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv,
static const struct v4l2_file_operations ts_fops =
{
.owner = THIS_MODULE,
- .open = ts_open,
- .release = ts_release,
- .read = ts_read,
- .poll = ts_poll,
- .mmap = ts_mmap,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
.ioctl = video_ioctl2,
};
@@ -247,12 +188,12 @@ static const struct v4l2_ioctl_ops ts_ioctl_ops = {
.vidioc_try_fmt_vid_cap = empress_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = empress_s_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = empress_g_fmt_vid_cap,
- .vidioc_reqbufs = saa7134_reqbufs,
- .vidioc_querybuf = saa7134_querybuf,
- .vidioc_qbuf = saa7134_qbuf,
- .vidioc_dqbuf = saa7134_dqbuf,
- .vidioc_streamon = saa7134_streamon,
- .vidioc_streamoff = saa7134_streamoff,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_g_frequency = saa7134_g_frequency,
.vidioc_s_frequency = saa7134_s_frequency,
.vidioc_g_tuner = saa7134_g_tuner,
@@ -262,6 +203,7 @@ static const struct v4l2_ioctl_ops ts_ioctl_ops = {
.vidioc_s_input = saa7134_s_input,
.vidioc_s_std = saa7134_s_std,
.vidioc_g_std = saa7134_g_std,
+ .vidioc_querystd = saa7134_querystd,
.vidioc_log_status = v4l2_ctrl_log_status,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
@@ -314,6 +256,7 @@ static bool empress_ctrl_filter(const struct v4l2_ctrl *ctrl)
static int empress_init(struct saa7134_dev *dev)
{
struct v4l2_ctrl_handler *hdl = &dev->empress_ctrl_handler;
+ struct vb2_queue *q;
int err;
dprintk("%s: %s\n",dev->name,__func__);
@@ -323,6 +266,7 @@ static int empress_init(struct saa7134_dev *dev)
*(dev->empress_dev) = saa7134_empress_template;
dev->empress_dev->v4l2_dev = &dev->v4l2_dev;
dev->empress_dev->release = video_device_release;
+ dev->empress_dev->lock = &dev->lock;
snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name),
"%s empress (%s)", dev->name,
saa7134_boards[dev->board].name);
@@ -339,6 +283,26 @@ static int empress_init(struct saa7134_dev *dev)
INIT_WORK(&dev->empress_workqueue, empress_signal_update);
+ q = &dev->empress_vbq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ /*
+ * Do not add VB2_USERPTR: the saa7134 DMA engine cannot handle
+ * transfers that do not start at the beginning of a page. A USERPTR
+ * can start anywhere in a page, so USERPTR support is a no-go.
+ */
+ q->io_modes = VB2_MMAP | VB2_READ;
+ q->drv_priv = &dev->ts_q;
+ q->ops = &saa7134_empress_qops;
+ q->gfp_flags = GFP_DMA32;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->buf_struct_size = sizeof(struct saa7134_buf);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &dev->lock;
+ err = vb2_queue_init(q);
+ if (err)
+ return err;
+ dev->empress_dev->queue = q;
+
video_set_drvdata(dev->empress_dev, dev);
err = video_register_device(dev->empress_dev,VFL_TYPE_GRABBER,
empress_nr[dev->nr]);
@@ -352,13 +316,6 @@ static int empress_init(struct saa7134_dev *dev)
printk(KERN_INFO "%s: registered device %s [mpeg]\n",
dev->name, video_device_node_name(dev->empress_dev));
- videobuf_queue_sg_init(&dev->empress_tsq, &saa7134_ts_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_ALTERNATE,
- sizeof(struct saa7134_buf),
- dev, NULL);
-
empress_signal_update(&dev->empress_workqueue);
return 0;
}
@@ -371,6 +328,7 @@ static int empress_fini(struct saa7134_dev *dev)
return 0;
flush_work(&dev->empress_workqueue);
video_unregister_device(dev->empress_dev);
+ vb2_queue_release(&dev->empress_vbq);
v4l2_ctrl_handler_free(&dev->empress_ctrl_handler);
dev->empress_dev = NULL;
return 0;
@@ -395,10 +353,3 @@ static void __exit empress_unregister(void)
module_init(empress_register);
module_exit(empress_unregister);
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c
index c68169d75804..f4da674e7f26 100644
--- a/drivers/media/pci/saa7134/saa7134-i2c.c
+++ b/drivers/media/pci/saa7134/saa7134-i2c.c
@@ -427,10 +427,3 @@ int saa7134_i2c_unregister(struct saa7134_dev *dev)
i2c_del_adapter(&dev->i2c_adap);
return 0;
}
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/saa7134/saa7134-reg.h b/drivers/media/pci/saa7134/saa7134-reg.h
index e7e0af101fa7..b6ea6f4f9b6c 100644
--- a/drivers/media/pci/saa7134/saa7134-reg.h
+++ b/drivers/media/pci/saa7134/saa7134-reg.h
@@ -167,17 +167,22 @@
#define SAA7134_HSYNC_START 0x106
#define SAA7134_HSYNC_STOP 0x107
#define SAA7134_SYNC_CTRL 0x108
+#define SAA7134_SYNC_CTRL_AUFD (1 << 7)
#define SAA7134_LUMA_CTRL 0x109
+#define SAA7134_LUMA_CTRL_LDEL (1 << 5)
#define SAA7134_DEC_LUMA_BRIGHT 0x10a
#define SAA7134_DEC_LUMA_CONTRAST 0x10b
#define SAA7134_DEC_CHROMA_SATURATION 0x10c
#define SAA7134_DEC_CHROMA_HUE 0x10d
#define SAA7134_CHROMA_CTRL1 0x10e
+#define SAA7134_CHROMA_CTRL1_AUTO0 (1 << 1)
+#define SAA7134_CHROMA_CTRL1_FCTC (1 << 2)
#define SAA7134_CHROMA_GAIN 0x10f
#define SAA7134_CHROMA_CTRL2 0x110
#define SAA7134_MODE_DELAY_CTRL 0x111
#define SAA7134_ANALOG_ADC 0x114
+#define SAA7134_ANALOG_ADC_AUTO1 (1 << 2)
#define SAA7134_VGATE_START 0x115
#define SAA7134_VGATE_STOP 0x116
#define SAA7134_MISC_VGATE_MSB 0x117
@@ -369,10 +374,3 @@
#define SAA7135_DSP_RWCLEAR_RERR 1
#define SAA7133_I2S_AUDIO_CONTROL 0x591
-/* ------------------------------------------------------------------ */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
-
diff --git a/drivers/media/pci/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c
index 2e3f4b412d8c..bd25323bd947 100644
--- a/drivers/media/pci/saa7134/saa7134-ts.c
+++ b/drivers/media/pci/saa7134/saa7134-ts.c
@@ -39,26 +39,29 @@ MODULE_PARM_DESC(ts_debug,"enable debug messages [ts]");
printk(KERN_DEBUG "%s/ts: " fmt, dev->name , ## arg)
/* ------------------------------------------------------------------ */
-
static int buffer_activate(struct saa7134_dev *dev,
struct saa7134_buf *buf,
struct saa7134_buf *next)
{
dprintk("buffer_activate [%p]",buf);
- buf->vb.state = VIDEOBUF_ACTIVE;
buf->top_seen = 0;
+ if (!dev->ts_started)
+ dev->ts_field = V4L2_FIELD_TOP;
+
if (NULL == next)
next = buf;
- if (V4L2_FIELD_TOP == buf->vb.field) {
+ if (V4L2_FIELD_TOP == dev->ts_field) {
dprintk("- [top] buf=%p next=%p\n",buf,next);
saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(buf));
saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(next));
+ dev->ts_field = V4L2_FIELD_BOTTOM;
} else {
dprintk("- [bottom] buf=%p next=%p\n",buf,next);
saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next));
saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf));
+ dev->ts_field = V4L2_FIELD_TOP;
}
/* start DMA */
@@ -72,96 +75,123 @@ static int buffer_activate(struct saa7134_dev *dev,
return 0;
}
-static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- enum v4l2_field field)
+int saa7134_ts_buffer_init(struct vb2_buffer *vb2)
{
- struct saa7134_dev *dev = q->priv_data;
- struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
+ struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
+
+ dmaq->curr = NULL;
+ buf->activate = buffer_activate;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_ts_buffer_init);
+
+int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2)
+{
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
+ struct sg_table *dma = vb2_dma_sg_plane_desc(vb2, 0);
unsigned int lines, llength, size;
- int err;
+ int ret;
- dprintk("buffer_prepare [%p,%s]\n",buf,v4l2_field_names[field]);
+ dprintk("buffer_prepare [%p]\n", buf);
llength = TS_PACKET_SIZE;
lines = dev->ts.nr_packets;
size = lines * llength;
- if (0 != buf->vb.baddr && buf->vb.bsize < size)
+ if (vb2_plane_size(vb2, 0) < size)
return -EINVAL;
- if (buf->vb.size != size) {
- saa7134_dma_free(q,buf);
- }
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
-
- struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
-
- dprintk("buffer_prepare: needs_init\n");
-
- buf->vb.width = llength;
- buf->vb.height = lines;
- buf->vb.size = size;
- buf->pt = &dev->ts.pt_ts;
-
- err = videobuf_iolock(q,&buf->vb,NULL);
- if (err)
- goto oops;
- err = saa7134_pgtable_build(dev->pci,buf->pt,
- dma->sglist,
- dma->sglen,
- saa7134_buffer_startpage(buf));
- if (err)
- goto oops;
- }
-
- buf->vb.state = VIDEOBUF_PREPARED;
- buf->activate = buffer_activate;
- buf->vb.field = field;
- return 0;
+ vb2_set_plane_payload(vb2, 0, size);
+ vb2->v4l2_buf.field = dev->field;
- oops:
- saa7134_dma_free(q,buf);
- return err;
+ ret = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
+ if (!ret)
+ return -EIO;
+ return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents,
+ saa7134_buffer_startpage(buf));
}
+EXPORT_SYMBOL_GPL(saa7134_ts_buffer_prepare);
-static int
-buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+void saa7134_ts_buffer_finish(struct vb2_buffer *vb2)
{
- struct saa7134_dev *dev = q->priv_data;
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
+ struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
- *size = TS_PACKET_SIZE * dev->ts.nr_packets;
- if (0 == *count)
- *count = dev->ts.nr_bufs;
- *count = saa7134_buffer_count(*size,*count);
+ dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
+}
+EXPORT_SYMBOL_GPL(saa7134_ts_buffer_finish);
+int saa7134_ts_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct saa7134_dmaqueue *dmaq = q->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ int size = TS_PACKET_SIZE * dev->ts.nr_packets;
+
+ if (0 == *nbuffers)
+ *nbuffers = dev->ts.nr_bufs;
+ *nbuffers = saa7134_buffer_count(size, *nbuffers);
+ if (*nbuffers < 3)
+ *nbuffers = 3;
+ *nplanes = 1;
+ sizes[0] = size;
return 0;
}
+EXPORT_SYMBOL_GPL(saa7134_ts_queue_setup);
-static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+int saa7134_ts_start_streaming(struct vb2_queue *vq, unsigned int count)
{
- struct saa7134_dev *dev = q->priv_data;
- struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
-
- saa7134_buffer_queue(dev,&dev->ts_q,buf);
+ struct saa7134_dmaqueue *dmaq = vq->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+
+ /*
+ * Planar video capture and TS share the same DMA channel,
+ * so only one can be active at a time.
+ */
+ if (vb2_is_busy(&dev->video_vbq) && dev->fmt->planar) {
+ struct saa7134_buf *buf, *tmp;
+
+ list_for_each_entry_safe(buf, tmp, &dmaq->queue, entry) {
+ list_del(&buf->entry);
+ vb2_buffer_done(&buf->vb2, VB2_BUF_STATE_QUEUED);
+ }
+ if (dmaq->curr) {
+ vb2_buffer_done(&dmaq->curr->vb2, VB2_BUF_STATE_QUEUED);
+ dmaq->curr = NULL;
+ }
+ return -EBUSY;
+ }
+ dmaq->seq_nr = 0;
+ return 0;
}
+EXPORT_SYMBOL_GPL(saa7134_ts_start_streaming);
-static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+void saa7134_ts_stop_streaming(struct vb2_queue *vq)
{
- struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
- struct saa7134_dev *dev = q->priv_data;
-
- if (dev->ts_started)
- saa7134_ts_stop(dev);
+ struct saa7134_dmaqueue *dmaq = vq->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
- saa7134_dma_free(q,buf);
+ saa7134_ts_stop(dev);
+ saa7134_stop_streaming(dev, dmaq);
}
-
-struct videobuf_queue_ops saa7134_ts_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
+EXPORT_SYMBOL_GPL(saa7134_ts_stop_streaming);
+
+struct vb2_ops saa7134_ts_qops = {
+ .queue_setup = saa7134_ts_queue_setup,
+ .buf_init = saa7134_ts_buffer_init,
+ .buf_prepare = saa7134_ts_buffer_prepare,
+ .buf_finish = saa7134_ts_buffer_finish,
+ .buf_queue = saa7134_vb2_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .stop_streaming = saa7134_ts_stop_streaming,
};
EXPORT_SYMBOL_GPL(saa7134_ts_qops);
@@ -213,7 +243,7 @@ int saa7134_ts_init1(struct saa7134_dev *dev)
dev->ts_q.dev = dev;
dev->ts_q.need_two = 1;
dev->ts_started = 0;
- saa7134_pgtable_alloc(dev->pci,&dev->ts.pt_ts);
+ saa7134_pgtable_alloc(dev->pci, &dev->ts_q.pt);
/* init TS hw */
saa7134_ts_init_hw(dev);
@@ -226,7 +256,8 @@ int saa7134_ts_stop(struct saa7134_dev *dev)
{
dprintk("TS stop\n");
- BUG_ON(!dev->ts_started);
+ if (!dev->ts_started)
+ return 0;
/* Stop TS stream */
switch (saa7134_boards[dev->board].ts_type) {
@@ -247,7 +278,8 @@ int saa7134_ts_start(struct saa7134_dev *dev)
{
dprintk("TS start\n");
- BUG_ON(dev->ts_started);
+ if (WARN_ON(dev->ts_started))
+ return 0;
/* dma: setup channel 5 (= TS) */
saa_writeb(SAA7134_TS_DMA0, (dev->ts.nr_packets - 1) & 0xff);
@@ -259,7 +291,7 @@ int saa7134_ts_start(struct saa7134_dev *dev)
saa_writel(SAA7134_RS_PITCH(5), TS_PACKET_SIZE);
saa_writel(SAA7134_RS_CONTROL(5), SAA7134_RS_CONTROL_BURST_16 |
SAA7134_RS_CONTROL_ME |
- (dev->ts.pt_ts.dma >> 12));
+ (dev->ts_q.pt.dma >> 12));
/* reset hardware TS buffers */
saa_writeb(SAA7134_TS_SERIAL1, 0x00);
@@ -293,7 +325,7 @@ int saa7134_ts_start(struct saa7134_dev *dev)
int saa7134_ts_fini(struct saa7134_dev *dev)
{
- saa7134_pgtable_free(dev->pci,&dev->ts.pt_ts);
+ saa7134_pgtable_free(dev->pci, &dev->ts_q.pt);
return 0;
}
@@ -303,25 +335,18 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
spin_lock(&dev->slock);
if (dev->ts_q.curr) {
- field = dev->ts_q.curr->vb.field;
- if (field == V4L2_FIELD_TOP) {
+ field = dev->ts_field;
+ if (field != V4L2_FIELD_TOP) {
if ((status & 0x100000) != 0x000000)
goto done;
} else {
if ((status & 0x100000) != 0x100000)
goto done;
}
- saa7134_buffer_finish(dev,&dev->ts_q,VIDEOBUF_DONE);
+ saa7134_buffer_finish(dev, &dev->ts_q, VB2_BUF_STATE_DONE);
}
saa7134_buffer_next(dev,&dev->ts_q);
done:
spin_unlock(&dev->slock);
}
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/saa7134/saa7134-tvaudio.c b/drivers/media/pci/saa7134/saa7134-tvaudio.c
index 0f34e09d98dc..3afbcb70b518 100644
--- a/drivers/media/pci/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/pci/saa7134/saa7134-tvaudio.c
@@ -1079,10 +1079,3 @@ int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
EXPORT_SYMBOL(saa_dsp_writel);
EXPORT_SYMBOL(saa7134_tvaudio_setmute);
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c
index d4da18d049f3..c06dbe17a87f 100644
--- a/drivers/media/pci/saa7134/saa7134-vbi.c
+++ b/drivers/media/pci/saa7134/saa7134-vbi.c
@@ -67,10 +67,10 @@ static void task_init(struct saa7134_dev *dev, struct saa7134_buf *buf,
saa_writeb(SAA7134_VBI_PHASE_OFFSET_LUMA(task), 0x00);
saa_writeb(SAA7134_VBI_PHASE_OFFSET_CHROMA(task), 0x00);
- saa_writeb(SAA7134_VBI_H_LEN1(task), buf->vb.width & 0xff);
- saa_writeb(SAA7134_VBI_H_LEN2(task), buf->vb.width >> 8);
- saa_writeb(SAA7134_VBI_V_LEN1(task), buf->vb.height & 0xff);
- saa_writeb(SAA7134_VBI_V_LEN2(task), buf->vb.height >> 8);
+ saa_writeb(SAA7134_VBI_H_LEN1(task), dev->vbi_hlen & 0xff);
+ saa_writeb(SAA7134_VBI_H_LEN2(task), dev->vbi_hlen >> 8);
+ saa_writeb(SAA7134_VBI_V_LEN1(task), dev->vbi_vlen & 0xff);
+ saa_writeb(SAA7134_VBI_V_LEN2(task), dev->vbi_vlen >> 8);
saa_andorb(SAA7134_DATA_PATH(task), 0xc0, 0x00);
}
@@ -81,14 +81,14 @@ static int buffer_activate(struct saa7134_dev *dev,
struct saa7134_buf *buf,
struct saa7134_buf *next)
{
- unsigned long control,base;
+ struct saa7134_dmaqueue *dmaq = buf->vb2.vb2_queue->drv_priv;
+ unsigned long control, base;
- dprintk("buffer_activate [%p]\n",buf);
- buf->vb.state = VIDEOBUF_ACTIVE;
+ dprintk("buffer_activate [%p]\n", buf);
buf->top_seen = 0;
- task_init(dev,buf,TASK_A);
- task_init(dev,buf,TASK_B);
+ task_init(dev, buf, TASK_A);
+ task_init(dev, buf, TASK_B);
saa_writeb(SAA7134_OFMT_DATA_A, 0x06);
saa_writeb(SAA7134_OFMT_DATA_B, 0x06);
@@ -96,107 +96,99 @@ static int buffer_activate(struct saa7134_dev *dev,
base = saa7134_buffer_base(buf);
control = SAA7134_RS_CONTROL_BURST_16 |
SAA7134_RS_CONTROL_ME |
- (buf->pt->dma >> 12);
- saa_writel(SAA7134_RS_BA1(2),base);
- saa_writel(SAA7134_RS_BA2(2),base + buf->vb.size/2);
- saa_writel(SAA7134_RS_PITCH(2),buf->vb.width);
- saa_writel(SAA7134_RS_CONTROL(2),control);
- saa_writel(SAA7134_RS_BA1(3),base);
- saa_writel(SAA7134_RS_BA2(3),base + buf->vb.size/2);
- saa_writel(SAA7134_RS_PITCH(3),buf->vb.width);
- saa_writel(SAA7134_RS_CONTROL(3),control);
+ (dmaq->pt.dma >> 12);
+ saa_writel(SAA7134_RS_BA1(2), base);
+ saa_writel(SAA7134_RS_BA2(2), base + dev->vbi_hlen * dev->vbi_vlen);
+ saa_writel(SAA7134_RS_PITCH(2), dev->vbi_hlen);
+ saa_writel(SAA7134_RS_CONTROL(2), control);
+ saa_writel(SAA7134_RS_BA1(3), base);
+ saa_writel(SAA7134_RS_BA2(3), base + dev->vbi_hlen * dev->vbi_vlen);
+ saa_writel(SAA7134_RS_PITCH(3), dev->vbi_hlen);
+ saa_writel(SAA7134_RS_CONTROL(3), control);
/* start DMA */
saa7134_set_dmabits(dev);
- mod_timer(&dev->vbi_q.timeout, jiffies+BUFFER_TIMEOUT);
+ mod_timer(&dmaq->timeout, jiffies + BUFFER_TIMEOUT);
return 0;
}
-static int buffer_prepare(struct videobuf_queue *q,
- struct videobuf_buffer *vb,
- enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb2)
{
- struct saa7134_dev *dev = q->priv_data;
- struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
- struct saa7134_tvnorm *norm = dev->tvnorm;
- unsigned int lines, llength, size;
- int err;
-
- lines = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1;
- if (lines > VBI_LINE_COUNT)
- lines = VBI_LINE_COUNT;
- llength = VBI_LINE_LENGTH;
- size = lines * llength * 2;
- if (0 != buf->vb.baddr && buf->vb.bsize < size)
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
+ struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
+ unsigned int size;
+ int ret;
+
+ if (dma->sgl->offset) {
+ pr_err("The buffer is not page-aligned\n");
return -EINVAL;
-
- if (buf->vb.size != size)
- saa7134_dma_free(q,buf);
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
-
- buf->vb.width = llength;
- buf->vb.height = lines;
- buf->vb.size = size;
- buf->pt = &dev->pt_vbi;
-
- err = videobuf_iolock(q,&buf->vb,NULL);
- if (err)
- goto oops;
- err = saa7134_pgtable_build(dev->pci,buf->pt,
- dma->sglist,
- dma->sglen,
- saa7134_buffer_startpage(buf));
- if (err)
- goto oops;
}
- buf->vb.state = VIDEOBUF_PREPARED;
- buf->activate = buffer_activate;
- buf->vb.field = field;
- return 0;
+ size = dev->vbi_hlen * dev->vbi_vlen * 2;
+ if (vb2_plane_size(vb2, 0) < size)
+ return -EINVAL;
+
+ vb2_set_plane_payload(vb2, 0, size);
- oops:
- saa7134_dma_free(q,buf);
- return err;
+ ret = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
+ if (!ret)
+ return -EIO;
+ return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents,
+ saa7134_buffer_startpage(buf));
}
-static int
-buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct saa7134_dev *dev = q->priv_data;
- int llength,lines;
-
- lines = dev->tvnorm->vbi_v_stop_0 - dev->tvnorm->vbi_v_start_0 +1;
- llength = VBI_LINE_LENGTH;
- *size = lines * llength * 2;
- if (0 == *count)
- *count = vbibufs;
- *count = saa7134_buffer_count(*size,*count);
+ struct saa7134_dmaqueue *dmaq = q->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ unsigned int size;
+
+ dev->vbi_vlen = dev->tvnorm->vbi_v_stop_0 - dev->tvnorm->vbi_v_start_0 + 1;
+ if (dev->vbi_vlen > VBI_LINE_COUNT)
+ dev->vbi_vlen = VBI_LINE_COUNT;
+ dev->vbi_hlen = VBI_LINE_LENGTH;
+ size = dev->vbi_hlen * dev->vbi_vlen * 2;
+
+ *nbuffers = saa7134_buffer_count(size, *nbuffers);
+ *nplanes = 1;
+ sizes[0] = size;
return 0;
}
-static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static int buffer_init(struct vb2_buffer *vb2)
{
- struct saa7134_dev *dev = q->priv_data;
- struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
+ struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
- saa7134_buffer_queue(dev,&dev->vbi_q,buf);
+ dmaq->curr = NULL;
+ buf->activate = buffer_activate;
+ return 0;
}
-static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static void buffer_finish(struct vb2_buffer *vb2)
{
- struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
+ struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
- saa7134_dma_free(q,buf);
+ dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
}
-struct videobuf_queue_ops saa7134_vbi_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
+struct vb2_ops saa7134_vbi_qops = {
+ .queue_setup = queue_setup,
+ .buf_init = buffer_init,
+ .buf_prepare = buffer_prepare,
+ .buf_finish = buffer_finish,
+ .buf_queue = saa7134_vb2_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = saa7134_vb2_start_streaming,
+ .stop_streaming = saa7134_vb2_stop_streaming,
};
/* ------------------------------------------------------------------ */
@@ -226,7 +218,6 @@ void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status)
{
spin_lock(&dev->slock);
if (dev->vbi_q.curr) {
- dev->vbi_fieldcount++;
/* make sure we have seen both fields */
if ((status & 0x10) == 0x00) {
dev->vbi_q.curr->top_seen = 1;
@@ -235,18 +226,10 @@ void saa7134_irq_vbi_done(struct saa7134_dev *dev, unsigned long status)
if (!dev->vbi_q.curr->top_seen)
goto done;
- dev->vbi_q.curr->vb.field_count = dev->vbi_fieldcount;
- saa7134_buffer_finish(dev,&dev->vbi_q,VIDEOBUF_DONE);
+ saa7134_buffer_finish(dev, &dev->vbi_q, VB2_BUF_STATE_DONE);
}
- saa7134_buffer_next(dev,&dev->vbi_q);
+ saa7134_buffer_next(dev, &dev->vbi_q);
done:
spin_unlock(&dev->slock);
}
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index eb472b5b26a0..d37599980768 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -381,42 +381,6 @@ static struct saa7134_format* format_by_fourcc(unsigned int fourcc)
return NULL;
}
-/* ----------------------------------------------------------------------- */
-/* resource management */
-
-static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bit)
-{
- if (fh->resources & bit)
- /* have it already allocated */
- return 1;
-
- /* is it free? */
- mutex_lock(&dev->lock);
- if (dev->resources & bit) {
- /* no, someone else uses it */
- mutex_unlock(&dev->lock);
- return 0;
- }
- /* it's free, grab it */
- fh->resources |= bit;
- dev->resources |= bit;
- dprintk("res: get %d\n",bit);
- mutex_unlock(&dev->lock);
- return 1;
-}
-
-static
-void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
-{
- BUG_ON((fh->resources & bits) != bits);
-
- mutex_lock(&dev->lock);
- fh->resources &= ~bits;
- dev->resources &= ~bits;
- dprintk("res: put %d\n",bits);
- mutex_unlock(&dev->lock);
-}
-
/* ------------------------------------------------------------------ */
static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
@@ -452,19 +416,26 @@ static void video_mux(struct saa7134_dev *dev, int input)
static void saa7134_set_decoder(struct saa7134_dev *dev)
{
- int luma_control, sync_control, mux;
+ int luma_control, sync_control, chroma_ctrl1, mux;
struct saa7134_tvnorm *norm = dev->tvnorm;
mux = card_in(dev, dev->ctl_input).vmux;
luma_control = norm->luma_control;
sync_control = norm->sync_control;
+ chroma_ctrl1 = norm->chroma_ctrl1;
if (mux > 5)
luma_control |= 0x80; /* svideo */
if (noninterlaced || dev->nosignal)
sync_control |= 0x20;
+ /* switch on auto standard detection */
+ sync_control |= SAA7134_SYNC_CTRL_AUFD;
+ chroma_ctrl1 |= SAA7134_CHROMA_CTRL1_AUTO0;
+ chroma_ctrl1 &= ~SAA7134_CHROMA_CTRL1_FCTC;
+ luma_control &= ~SAA7134_LUMA_CTRL_LDEL;
+
/* setup video decoder */
saa_writeb(SAA7134_INCR_DELAY, 0x08);
saa_writeb(SAA7134_ANALOG_IN_CTRL1, 0xc0 | mux);
@@ -487,7 +458,7 @@ static void saa7134_set_decoder(struct saa7134_dev *dev)
dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue);
- saa_writeb(SAA7134_CHROMA_CTRL1, norm->chroma_ctrl1);
+ saa_writeb(SAA7134_CHROMA_CTRL1, chroma_ctrl1);
saa_writeb(SAA7134_CHROMA_GAIN, norm->chroma_gain);
saa_writeb(SAA7134_CHROMA_CTRL2, norm->chroma_ctrl2);
@@ -506,10 +477,10 @@ void saa7134_set_tvnorm_hw(struct saa7134_dev *dev)
saa7134_set_decoder(dev);
if (card_in(dev, dev->ctl_input).tv)
- saa_call_all(dev, core, s_std, dev->tvnorm->id);
+ saa_call_all(dev, video, s_std, dev->tvnorm->id);
/* Set the correct norm for the saa6752hs. This function
does nothing if there is no saa6752hs. */
- saa_call_empress(dev, core, s_std, dev->tvnorm->id);
+ saa_call_empress(dev, video, s_std, dev->tvnorm->id);
}
static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
@@ -817,35 +788,35 @@ static int buffer_activate(struct saa7134_dev *dev,
struct saa7134_buf *buf,
struct saa7134_buf *next)
{
+ struct saa7134_dmaqueue *dmaq = buf->vb2.vb2_queue->drv_priv;
unsigned long base,control,bpl;
unsigned long bpl_uv,lines_uv,base2,base3,tmp; /* planar */
dprintk("buffer_activate buf=%p\n",buf);
- buf->vb.state = VIDEOBUF_ACTIVE;
buf->top_seen = 0;
- set_size(dev,TASK_A,buf->vb.width,buf->vb.height,
- V4L2_FIELD_HAS_BOTH(buf->vb.field));
- if (buf->fmt->yuv)
+ set_size(dev, TASK_A, dev->width, dev->height,
+ V4L2_FIELD_HAS_BOTH(dev->field));
+ if (dev->fmt->yuv)
saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x03);
else
saa_andorb(SAA7134_DATA_PATH(TASK_A), 0x3f, 0x01);
- saa_writeb(SAA7134_OFMT_VIDEO_A, buf->fmt->pm);
+ saa_writeb(SAA7134_OFMT_VIDEO_A, dev->fmt->pm);
/* DMA: setup channel 0 (= Video Task A0) */
base = saa7134_buffer_base(buf);
- if (buf->fmt->planar)
- bpl = buf->vb.width;
+ if (dev->fmt->planar)
+ bpl = dev->width;
else
- bpl = (buf->vb.width * buf->fmt->depth) / 8;
+ bpl = (dev->width * dev->fmt->depth) / 8;
control = SAA7134_RS_CONTROL_BURST_16 |
SAA7134_RS_CONTROL_ME |
- (buf->pt->dma >> 12);
- if (buf->fmt->bswap)
+ (dmaq->pt.dma >> 12);
+ if (dev->fmt->bswap)
control |= SAA7134_RS_CONTROL_BSWAP;
- if (buf->fmt->wswap)
+ if (dev->fmt->wswap)
control |= SAA7134_RS_CONTROL_WSWAP;
- if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) {
+ if (V4L2_FIELD_HAS_BOTH(dev->field)) {
/* interlaced */
saa_writel(SAA7134_RS_BA1(0),base);
saa_writel(SAA7134_RS_BA2(0),base+bpl);
@@ -858,17 +829,17 @@ static int buffer_activate(struct saa7134_dev *dev,
}
saa_writel(SAA7134_RS_CONTROL(0),control);
- if (buf->fmt->planar) {
+ if (dev->fmt->planar) {
/* DMA: setup channel 4+5 (= planar task A) */
- bpl_uv = bpl >> buf->fmt->hshift;
- lines_uv = buf->vb.height >> buf->fmt->vshift;
- base2 = base + bpl * buf->vb.height;
+ bpl_uv = bpl >> dev->fmt->hshift;
+ lines_uv = dev->height >> dev->fmt->vshift;
+ base2 = base + bpl * dev->height;
base3 = base2 + bpl_uv * lines_uv;
- if (buf->fmt->uvswap)
+ if (dev->fmt->uvswap)
tmp = base2, base2 = base3, base3 = tmp;
dprintk("uv: bpl=%ld lines=%ld base2/3=%ld/%ld\n",
bpl_uv,lines_uv,base2,base3);
- if (V4L2_FIELD_HAS_BOTH(buf->vb.field)) {
+ if (V4L2_FIELD_HAS_BOTH(dev->field)) {
/* interlaced */
saa_writel(SAA7134_RS_BA1(4),base2);
saa_writel(SAA7134_RS_BA2(4),base2+bpl_uv);
@@ -891,22 +862,65 @@ static int buffer_activate(struct saa7134_dev *dev,
/* start DMA */
saa7134_set_dmabits(dev);
- mod_timer(&dev->video_q.timeout, jiffies+BUFFER_TIMEOUT);
+ mod_timer(&dmaq->timeout, jiffies + BUFFER_TIMEOUT);
+ return 0;
+}
+
+static int buffer_init(struct vb2_buffer *vb2)
+{
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
+ struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
+
+ dmaq->curr = NULL;
+ buf->activate = buffer_activate;
return 0;
}
-static int buffer_prepare(struct videobuf_queue *q,
- struct videobuf_buffer *vb,
- enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb2)
{
- struct saa7134_dev *dev = q->priv_data;
- struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
+ struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
unsigned int size;
- int err;
+ int ret;
- /* sanity checks */
- if (NULL == dev->fmt)
+ if (dma->sgl->offset) {
+ pr_err("The buffer is not page-aligned\n");
return -EINVAL;
+ }
+ size = (dev->width * dev->height * dev->fmt->depth) >> 3;
+ if (vb2_plane_size(vb2, 0) < size)
+ return -EINVAL;
+
+ vb2_set_plane_payload(vb2, 0, size);
+ vb2->v4l2_buf.field = dev->field;
+
+ ret = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
+ if (!ret)
+ return -EIO;
+ return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents,
+ saa7134_buffer_startpage(buf));
+}
+
+static void buffer_finish(struct vb2_buffer *vb2)
+{
+ struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
+ struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
+
+ dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
+}
+
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct saa7134_dmaqueue *dmaq = q->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ int size = dev->fmt->depth * dev->width * dev->height >> 3;
+
if (dev->width < 48 ||
dev->height < 32 ||
dev->width/4 > dev->crop_current.width ||
@@ -914,83 +928,88 @@ static int buffer_prepare(struct videobuf_queue *q,
dev->width > dev->crop_bounds.width ||
dev->height > dev->crop_bounds.height)
return -EINVAL;
- size = (dev->width * dev->height * dev->fmt->depth) >> 3;
- if (0 != buf->vb.baddr && buf->vb.bsize < size)
- return -EINVAL;
-
- dprintk("buffer_prepare [%d,size=%dx%d,bytes=%d,fields=%s,%s]\n",
- vb->i, dev->width, dev->height, size, v4l2_field_names[field],
- dev->fmt->name);
- if (buf->vb.width != dev->width ||
- buf->vb.height != dev->height ||
- buf->vb.size != size ||
- buf->vb.field != field ||
- buf->fmt != dev->fmt) {
- saa7134_dma_free(q,buf);
- }
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
-
- buf->vb.width = dev->width;
- buf->vb.height = dev->height;
- buf->vb.size = size;
- buf->vb.field = field;
- buf->fmt = dev->fmt;
- buf->pt = &dev->pt_cap;
- dev->video_q.curr = NULL;
-
- err = videobuf_iolock(q,&buf->vb,&dev->ovbuf);
- if (err)
- goto oops;
- err = saa7134_pgtable_build(dev->pci,buf->pt,
- dma->sglist,
- dma->sglen,
- saa7134_buffer_startpage(buf));
- if (err)
- goto oops;
- }
- buf->vb.state = VIDEOBUF_PREPARED;
- buf->activate = buffer_activate;
+ *nbuffers = saa7134_buffer_count(size, *nbuffers);
+ *nplanes = 1;
+ sizes[0] = size;
return 0;
-
- oops:
- saa7134_dma_free(q,buf);
- return err;
}
-static int
-buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+/*
+ * move buffer to hardware queue
+ */
+void saa7134_vb2_buffer_queue(struct vb2_buffer *vb)
{
- struct saa7134_dev *dev = q->priv_data;
+ struct saa7134_dmaqueue *dmaq = vb->vb2_queue->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+ struct saa7134_buf *buf = container_of(vb, struct saa7134_buf, vb2);
- *size = dev->fmt->depth * dev->width * dev->height >> 3;
- if (0 == *count)
- *count = gbuffers;
- *count = saa7134_buffer_count(*size,*count);
- return 0;
+ saa7134_buffer_queue(dev, dmaq, buf);
}
+EXPORT_SYMBOL_GPL(saa7134_vb2_buffer_queue);
-static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+int saa7134_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
{
- struct saa7134_dev *dev = q->priv_data;
- struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+ struct saa7134_dmaqueue *dmaq = vq->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+
+ /*
+ * Planar video capture and TS share the same DMA channel,
+ * so only one can be active at a time.
+ */
+ if (card_is_empress(dev) && vb2_is_busy(&dev->empress_vbq) &&
+ dmaq == &dev->video_q && dev->fmt->planar) {
+ struct saa7134_buf *buf, *tmp;
- saa7134_buffer_queue(dev, &dev->video_q, buf);
+ list_for_each_entry_safe(buf, tmp, &dmaq->queue, entry) {
+ list_del(&buf->entry);
+ vb2_buffer_done(&buf->vb2, VB2_BUF_STATE_QUEUED);
+ }
+ if (dmaq->curr) {
+ vb2_buffer_done(&dmaq->curr->vb2, VB2_BUF_STATE_QUEUED);
+ dmaq->curr = NULL;
+ }
+ return -EBUSY;
+ }
+
+ /* The SAA7134 has a 1K FIFO; the datasheet suggests that when
+ * configured conservatively, there's 22 usec of buffering for video.
+ * We therefore request a DMA latency of 20 usec, giving us 2 usec of
+ * margin in case the FIFO is configured differently to the datasheet.
+ * Unfortunately, I lack register-level documentation to check the
+ * Linux FIFO setup and confirm the perfect value.
+ */
+ if ((dmaq == &dev->video_q && !vb2_is_streaming(&dev->vbi_vbq)) ||
+ (dmaq == &dev->vbi_q && !vb2_is_streaming(&dev->video_vbq)))
+ pm_qos_add_request(&dev->qos_request,
+ PM_QOS_CPU_DMA_LATENCY, 20);
+ dmaq->seq_nr = 0;
+
+ return 0;
}
-static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+void saa7134_vb2_stop_streaming(struct vb2_queue *vq)
{
- struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
+ struct saa7134_dmaqueue *dmaq = vq->drv_priv;
+ struct saa7134_dev *dev = dmaq->dev;
+
+ saa7134_stop_streaming(dev, dmaq);
- saa7134_dma_free(q,buf);
+ if ((dmaq == &dev->video_q && !vb2_is_streaming(&dev->vbi_vbq)) ||
+ (dmaq == &dev->vbi_q && !vb2_is_streaming(&dev->video_vbq)))
+ pm_qos_remove_request(&dev->qos_request);
}
-static struct videobuf_queue_ops video_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
+static struct vb2_ops vb2_qops = {
+ .queue_setup = queue_setup,
+ .buf_init = buffer_init,
+ .buf_prepare = buffer_prepare,
+ .buf_finish = buffer_finish,
+ .buf_queue = saa7134_vb2_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = saa7134_vb2_start_streaming,
+ .stop_streaming = saa7134_vb2_stop_streaming,
};
/* ------------------------------------------------------------------ */
@@ -1068,7 +1087,7 @@ static int saa7134_s_ctrl(struct v4l2_ctrl *ctrl)
default:
return -EINVAL;
}
- if (restart_overlay && res_locked(dev, RESOURCE_OVERLAY)) {
+ if (restart_overlay && dev->overlay_owner) {
spin_lock_irqsave(&dev->slock, flags);
stop_preview(dev);
start_preview(dev);
@@ -1079,182 +1098,57 @@ static int saa7134_s_ctrl(struct v4l2_ctrl *ctrl)
/* ------------------------------------------------------------------ */
-static struct videobuf_queue *saa7134_queue(struct file *file)
+static inline struct vb2_queue *saa7134_queue(struct file *file)
{
- struct video_device *vdev = video_devdata(file);
- struct saa7134_dev *dev = video_drvdata(file);
- struct saa7134_fh *fh = file->private_data;
- struct videobuf_queue *q = NULL;
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_GRABBER:
- q = fh->is_empress ? &dev->empress_tsq : &dev->cap;
- break;
- case VFL_TYPE_VBI:
- q = &dev->vbi;
- break;
- default:
- BUG();
- }
- return q;
-}
-
-static int saa7134_resource(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct saa7134_fh *fh = file->private_data;
-
- if (vdev->vfl_type == VFL_TYPE_GRABBER)
- return fh->is_empress ? RESOURCE_EMPRESS : RESOURCE_VIDEO;
-
- if (vdev->vfl_type == VFL_TYPE_VBI)
- return RESOURCE_VBI;
-
- BUG();
- return 0;
+ return video_devdata(file)->queue;
}
static int video_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct saa7134_dev *dev = video_drvdata(file);
- struct saa7134_fh *fh;
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh),GFP_KERNEL);
- if (NULL == fh)
- return -ENOMEM;
+ int ret = v4l2_fh_open(file);
- v4l2_fh_init(&fh->fh, vdev);
- file->private_data = fh;
+ if (ret < 0)
+ return ret;
+ mutex_lock(&dev->lock);
if (vdev->vfl_type == VFL_TYPE_RADIO) {
/* switch to radio mode */
- saa7134_tvaudio_setinput(dev,&card(dev).radio);
+ saa7134_tvaudio_setinput(dev, &card(dev).radio);
saa_call_all(dev, tuner, s_radio);
} else {
/* switch to video/vbi mode */
- video_mux(dev,dev->ctl_input);
+ video_mux(dev, dev->ctl_input);
}
- v4l2_fh_add(&fh->fh);
+ mutex_unlock(&dev->lock);
return 0;
}
-static ssize_t
-video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
-{
- struct video_device *vdev = video_devdata(file);
- struct saa7134_dev *dev = video_drvdata(file);
- struct saa7134_fh *fh = file->private_data;
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_GRABBER:
- if (res_locked(dev, RESOURCE_VIDEO))
- return -EBUSY;
- return videobuf_read_one(saa7134_queue(file),
- data, count, ppos,
- file->f_flags & O_NONBLOCK);
- case VFL_TYPE_VBI:
- if (!res_get(dev, fh, RESOURCE_VBI))
- return -EBUSY;
- return videobuf_read_stream(saa7134_queue(file),
- data, count, ppos, 1,
- file->f_flags & O_NONBLOCK);
- break;
- default:
- BUG();
- return 0;
- }
-}
-
-static unsigned int
-video_poll(struct file *file, struct poll_table_struct *wait)
-{
- unsigned long req_events = poll_requested_events(wait);
- struct video_device *vdev = video_devdata(file);
- struct saa7134_dev *dev = video_drvdata(file);
- struct saa7134_fh *fh = file->private_data;
- struct videobuf_buffer *buf = NULL;
- unsigned int rc = 0;
-
- if (v4l2_event_pending(&fh->fh))
- rc = POLLPRI;
- else if (req_events & POLLPRI)
- poll_wait(file, &fh->fh.wait, wait);
-
- if (vdev->vfl_type == VFL_TYPE_VBI)
- return rc | videobuf_poll_stream(file, &dev->vbi, wait);
-
- if (res_check(fh, RESOURCE_VIDEO)) {
- mutex_lock(&dev->cap.vb_lock);
- if (!list_empty(&dev->cap.stream))
- buf = list_entry(dev->cap.stream.next, struct videobuf_buffer, stream);
- } else {
- mutex_lock(&dev->cap.vb_lock);
- if (UNSET == dev->cap.read_off) {
- /* need to capture a new frame */
- if (res_locked(dev, RESOURCE_VIDEO))
- goto err;
- if (0 != dev->cap.ops->buf_prepare(&dev->cap,
- dev->cap.read_buf, dev->cap.field))
- goto err;
- dev->cap.ops->buf_queue(&dev->cap, dev->cap.read_buf);
- dev->cap.read_off = 0;
- }
- buf = dev->cap.read_buf;
- }
-
- if (!buf)
- goto err;
-
- poll_wait(file, &buf->done, wait);
- if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR)
- rc |= POLLIN | POLLRDNORM;
- mutex_unlock(&dev->cap.vb_lock);
- return rc;
-
-err:
- mutex_unlock(&dev->cap.vb_lock);
- return rc | POLLERR;
-}
-
static int video_release(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct saa7134_dev *dev = video_drvdata(file);
- struct saa7134_fh *fh = file->private_data;
+ struct v4l2_fh *fh = file->private_data;
struct saa6588_command cmd;
unsigned long flags;
+ mutex_lock(&dev->lock);
saa7134_tvaudio_close(dev);
/* turn off overlay */
- if (res_check(fh, RESOURCE_OVERLAY)) {
+ if (fh == dev->overlay_owner) {
spin_lock_irqsave(&dev->slock,flags);
stop_preview(dev);
spin_unlock_irqrestore(&dev->slock,flags);
- res_free(dev, fh, RESOURCE_OVERLAY);
- }
-
- /* stop video capture */
- if (res_check(fh, RESOURCE_VIDEO)) {
- pm_qos_remove_request(&dev->qos_request);
- videobuf_streamoff(&dev->cap);
- res_free(dev, fh, RESOURCE_VIDEO);
- videobuf_mmap_free(&dev->cap);
- }
- if (dev->cap.read_buf) {
- buffer_release(&dev->cap, dev->cap.read_buf);
- kfree(dev->cap.read_buf);
+ dev->overlay_owner = NULL;
}
- /* stop vbi capture */
- if (res_check(fh, RESOURCE_VBI)) {
- videobuf_stop(&dev->vbi);
- res_free(dev, fh, RESOURCE_VBI);
- videobuf_mmap_free(&dev->vbi);
- }
+ if (vdev->vfl_type == VFL_TYPE_RADIO)
+ v4l2_fh_release(file);
+ else
+ _vb2_fop_release(file, NULL);
/* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/
saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0);
@@ -1265,19 +1159,11 @@ static int video_release(struct file *file)
saa_call_all(dev, core, s_power, 0);
if (vdev->vfl_type == VFL_TYPE_RADIO)
saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
+ mutex_unlock(&dev->lock);
- v4l2_fh_del(&fh->fh);
- v4l2_fh_exit(&fh->fh);
- file->private_data = NULL;
- kfree(fh);
return 0;
}
-static int video_mmap(struct file *file, struct vm_area_struct * vma)
-{
- return videobuf_mmap_mapper(saa7134_queue(file), vma);
-}
-
static ssize_t radio_read(struct file *file, char __user *data,
size_t count, loff_t *ppos)
{
@@ -1290,7 +1176,9 @@ static ssize_t radio_read(struct file *file, char __user *data,
cmd.instance = file;
cmd.result = -ENODEV;
+ mutex_lock(&dev->lock);
saa_call_all(dev, core, ioctl, SAA6588_CMD_READ, &cmd);
+ mutex_unlock(&dev->lock);
return cmd.result;
}
@@ -1304,7 +1192,9 @@ static unsigned int radio_poll(struct file *file, poll_table *wait)
cmd.instance = file;
cmd.event_list = wait;
cmd.result = 0;
+ mutex_lock(&dev->lock);
saa_call_all(dev, core, ioctl, SAA6588_CMD_POLL, &cmd);
+ mutex_unlock(&dev->lock);
return rc | cmd.result;
}
@@ -1338,7 +1228,7 @@ static int saa7134_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.width = dev->width;
f->fmt.pix.height = dev->height;
- f->fmt.pix.field = dev->cap.field;
+ f->fmt.pix.field = dev->field;
f->fmt.pix.pixelformat = dev->fmt->fourcc;
f->fmt.pix.bytesperline =
(f->fmt.pix.width * dev->fmt->depth) >> 3;
@@ -1362,7 +1252,6 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
return -EINVAL;
}
- mutex_lock(&dev->lock);
f->fmt.win = dev->win;
f->fmt.win.clips = clips;
if (clips == NULL)
@@ -1376,7 +1265,6 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
sizeof(struct v4l2_rect)))
err = -EFAULT;
}
- mutex_unlock(&dev->lock);
return err;
}
@@ -1457,10 +1345,10 @@ static int saa7134_s_fmt_vid_cap(struct file *file, void *priv,
if (0 != err)
return err;
- dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- dev->width = f->fmt.pix.width;
- dev->height = f->fmt.pix.height;
- dev->cap.field = f->fmt.pix.field;
+ dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ dev->width = f->fmt.pix.width;
+ dev->height = f->fmt.pix.height;
+ dev->field = f->fmt.pix.field;
return 0;
}
@@ -1481,25 +1369,20 @@ static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv,
if (0 != err)
return err;
- mutex_lock(&dev->lock);
-
dev->win = f->fmt.win;
dev->nclips = f->fmt.win.clipcount;
if (copy_from_user(dev->clips, f->fmt.win.clips,
- sizeof(struct v4l2_clip) * dev->nclips)) {
- mutex_unlock(&dev->lock);
+ sizeof(struct v4l2_clip) * dev->nclips))
return -EFAULT;
- }
- if (res_check(priv, RESOURCE_OVERLAY)) {
+ if (priv == dev->overlay_owner) {
spin_lock_irqsave(&dev->slock, flags);
stop_preview(dev);
start_preview(dev);
spin_unlock_irqrestore(&dev->slock, flags);
}
- mutex_unlock(&dev->lock);
return 0;
}
@@ -1551,9 +1434,7 @@ int saa7134_s_input(struct file *file, void *priv, unsigned int i)
return -EINVAL;
if (NULL == card_in(dev, i).name)
return -EINVAL;
- mutex_lock(&dev->lock);
video_mux(dev, i);
- mutex_unlock(&dev->lock);
return 0;
}
EXPORT_SYMBOL_GPL(saa7134_s_input);
@@ -1563,7 +1444,6 @@ int saa7134_querycap(struct file *file, void *priv,
{
struct saa7134_dev *dev = video_drvdata(file);
struct video_device *vdev = video_devdata(file);
- struct saa7134_fh *fh = priv;
u32 radio_caps, video_caps, vbi_caps;
unsigned int tuner_type = dev->tuner_type;
@@ -1582,7 +1462,7 @@ int saa7134_querycap(struct file *file, void *priv,
radio_caps |= V4L2_CAP_RDS_CAPTURE;
video_caps = V4L2_CAP_VIDEO_CAPTURE;
- if (saa7134_no_overlay <= 0 && !fh->is_empress)
+ if (saa7134_no_overlay <= 0 && !is_empress(file))
video_caps |= V4L2_CAP_VIDEO_OVERLAY;
vbi_caps = V4L2_CAP_VBI_CAPTURE;
@@ -1613,12 +1493,12 @@ EXPORT_SYMBOL_GPL(saa7134_querycap);
int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
{
struct saa7134_dev *dev = video_drvdata(file);
- struct saa7134_fh *fh = priv;
+ struct v4l2_fh *fh = priv;
unsigned long flags;
unsigned int i;
v4l2_std_id fixup;
- if (fh->is_empress && res_locked(dev, RESOURCE_OVERLAY)) {
+ if (is_empress(file) && dev->overlay_owner) {
/* Don't change the std from the mpeg device
if overlay is active. */
return -EBUSY;
@@ -1657,8 +1537,7 @@ int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
id = tvnorms[i].id;
- mutex_lock(&dev->lock);
- if (!fh->is_empress && res_check(fh, RESOURCE_OVERLAY)) {
+ if (!is_empress(file) && fh == dev->overlay_owner) {
spin_lock_irqsave(&dev->slock, flags);
stop_preview(dev);
spin_unlock_irqrestore(&dev->slock, flags);
@@ -1672,7 +1551,6 @@ int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
set_tvnorm(dev, &tvnorms[i]);
saa7134_tvaudio_do_scan(dev);
- mutex_unlock(&dev->lock);
return 0;
}
EXPORT_SYMBOL_GPL(saa7134_s_std);
@@ -1686,6 +1564,35 @@ int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id)
}
EXPORT_SYMBOL_GPL(saa7134_g_std);
+static v4l2_std_id saa7134_read_std(struct saa7134_dev *dev)
+{
+ static v4l2_std_id stds[] = {
+ V4L2_STD_UNKNOWN,
+ V4L2_STD_NTSC,
+ V4L2_STD_PAL,
+ V4L2_STD_SECAM };
+
+ v4l2_std_id result = 0;
+
+ u8 st1 = saa_readb(SAA7134_STATUS_VIDEO1);
+ u8 st2 = saa_readb(SAA7134_STATUS_VIDEO2);
+
+ if (!(st2 & 0x1)) /* RDCAP == 0 */
+ result = V4L2_STD_UNKNOWN;
+ else
+ result = stds[st1 & 0x03];
+
+ return result;
+}
+
+int saa7134_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct saa7134_dev *dev = video_drvdata(file);
+ *std &= saa7134_read_std(dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(saa7134_querystd);
+
static int saa7134_cropcap(struct file *file, void *priv,
struct v4l2_cropcap *cap)
{
@@ -1730,9 +1637,9 @@ static int saa7134_s_crop(struct file *file, void *f, const struct v4l2_crop *cr
crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
return -EINVAL;
- if (res_locked(dev, RESOURCE_OVERLAY))
+ if (dev->overlay_owner)
return -EBUSY;
- if (res_locked(dev, RESOURCE_VIDEO))
+ if (vb2_is_streaming(&dev->video_vbq))
return -EBUSY;
*c = crop->c;
@@ -1826,12 +1733,10 @@ int saa7134_s_frequency(struct file *file, void *priv,
if (0 != f->tuner)
return -EINVAL;
- mutex_lock(&dev->lock);
saa_call_all(dev, tuner, s_frequency, f);
saa7134_tvaudio_do_scan(dev);
- mutex_unlock(&dev->lock);
return 0;
}
EXPORT_SYMBOL_GPL(saa7134_s_frequency);
@@ -1915,92 +1820,24 @@ static int saa7134_overlay(struct file *file, void *priv, unsigned int on)
return -EINVAL;
}
- if (!res_get(dev, priv, RESOURCE_OVERLAY))
+ if (dev->overlay_owner && priv != dev->overlay_owner)
return -EBUSY;
+ dev->overlay_owner = priv;
spin_lock_irqsave(&dev->slock, flags);
start_preview(dev);
spin_unlock_irqrestore(&dev->slock, flags);
}
if (!on) {
- if (!res_check(priv, RESOURCE_OVERLAY))
+ if (priv != dev->overlay_owner)
return -EINVAL;
spin_lock_irqsave(&dev->slock, flags);
stop_preview(dev);
spin_unlock_irqrestore(&dev->slock, flags);
- res_free(dev, priv, RESOURCE_OVERLAY);
+ dev->overlay_owner = NULL;
}
return 0;
}
-int saa7134_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- return videobuf_reqbufs(saa7134_queue(file), p);
-}
-EXPORT_SYMBOL_GPL(saa7134_reqbufs);
-
-int saa7134_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *b)
-{
- return videobuf_querybuf(saa7134_queue(file), b);
-}
-EXPORT_SYMBOL_GPL(saa7134_querybuf);
-
-int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- return videobuf_qbuf(saa7134_queue(file), b);
-}
-EXPORT_SYMBOL_GPL(saa7134_qbuf);
-
-int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- return videobuf_dqbuf(saa7134_queue(file), b,
- file->f_flags & O_NONBLOCK);
-}
-EXPORT_SYMBOL_GPL(saa7134_dqbuf);
-
-int saa7134_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct saa7134_dev *dev = video_drvdata(file);
- int res = saa7134_resource(file);
-
- if (!res_get(dev, priv, res))
- return -EBUSY;
-
- /* The SAA7134 has a 1K FIFO; the datasheet suggests that when
- * configured conservatively, there's 22 usec of buffering for video.
- * We therefore request a DMA latency of 20 usec, giving us 2 usec of
- * margin in case the FIFO is configured differently to the datasheet.
- * Unfortunately, I lack register-level documentation to check the
- * Linux FIFO setup and confirm the perfect value.
- */
- if (res != RESOURCE_EMPRESS)
- pm_qos_add_request(&dev->qos_request,
- PM_QOS_CPU_DMA_LATENCY, 20);
-
- return videobuf_streamon(saa7134_queue(file));
-}
-EXPORT_SYMBOL_GPL(saa7134_streamon);
-
-int saa7134_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct saa7134_dev *dev = video_drvdata(file);
- int err;
- int res = saa7134_resource(file);
-
- if (res != RESOURCE_EMPRESS)
- pm_qos_remove_request(&dev->qos_request);
-
- err = videobuf_streamoff(saa7134_queue(file));
- if (err < 0)
- return err;
- res_free(dev, priv, res);
- return 0;
-}
-EXPORT_SYMBOL_GPL(saa7134_streamoff);
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_register (struct file *file, void *priv,
struct v4l2_dbg_register *reg)
@@ -2058,10 +1895,10 @@ static const struct v4l2_file_operations video_fops =
.owner = THIS_MODULE,
.open = video_open,
.release = video_release,
- .read = video_read,
- .poll = video_poll,
- .mmap = video_mmap,
- .ioctl = video_ioctl2,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -2078,17 +1915,18 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_try_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
.vidioc_s_fmt_vbi_cap = saa7134_try_get_set_fmt_vbi_cap,
.vidioc_cropcap = saa7134_cropcap,
- .vidioc_reqbufs = saa7134_reqbufs,
- .vidioc_querybuf = saa7134_querybuf,
- .vidioc_qbuf = saa7134_qbuf,
- .vidioc_dqbuf = saa7134_dqbuf,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_s_std = saa7134_s_std,
.vidioc_g_std = saa7134_g_std,
+ .vidioc_querystd = saa7134_querystd,
.vidioc_enum_input = saa7134_enum_input,
.vidioc_g_input = saa7134_g_input,
.vidioc_s_input = saa7134_s_input,
- .vidioc_streamon = saa7134_streamon,
- .vidioc_streamoff = saa7134_streamoff,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_g_tuner = saa7134_g_tuner,
.vidioc_s_tuner = saa7134_s_tuner,
.vidioc_g_crop = saa7134_g_crop,
@@ -2112,7 +1950,7 @@ static const struct v4l2_file_operations radio_fops = {
.open = video_open,
.read = radio_read,
.release = video_release,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.poll = radio_poll,
};
@@ -2190,6 +2028,8 @@ static const struct v4l2_ctrl_config saa7134_ctrl_automute = {
int saa7134_video_init1(struct saa7134_dev *dev)
{
struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
+ struct vb2_queue *q;
+ int ret;
/* sanitycheck insmod options */
if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
@@ -2241,6 +2081,7 @@ int saa7134_video_init1(struct saa7134_dev *dev)
dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
dev->width = 720;
dev->height = 576;
+ dev->field = V4L2_FIELD_INTERLACED;
dev->win.w.width = dev->width;
dev->win.w.height = dev->height;
dev->win.field = V4L2_FIELD_INTERLACED;
@@ -2252,20 +2093,47 @@ int saa7134_video_init1(struct saa7134_dev *dev)
if (saa7134_boards[dev->board].video_out)
saa7134_videoport_init(dev);
- videobuf_queue_sg_init(&dev->cap, &video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct saa7134_buf),
- dev, NULL);
- videobuf_queue_sg_init(&dev->vbi, &saa7134_vbi_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VBI_CAPTURE,
- V4L2_FIELD_SEQ_TB,
- sizeof(struct saa7134_buf),
- dev, NULL);
- saa7134_pgtable_alloc(dev->pci, &dev->pt_cap);
- saa7134_pgtable_alloc(dev->pci, &dev->pt_vbi);
+ q = &dev->video_vbq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ /*
+ * Do not add VB2_USERPTR unless explicitly requested: the saa7134 DMA
+ * engine cannot handle transfers that do not start at the beginning
+ * of a page. A user-provided pointer can start anywhere in a page, so
+ * USERPTR support is a no-go unless the application knows about these
+ * limitations and has special support for this.
+ */
+ q->io_modes = VB2_MMAP | VB2_READ;
+ if (saa7134_userptr)
+ q->io_modes |= VB2_USERPTR;
+ q->drv_priv = &dev->video_q;
+ q->ops = &vb2_qops;
+ q->gfp_flags = GFP_DMA32;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->buf_struct_size = sizeof(struct saa7134_buf);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &dev->lock;
+ ret = vb2_queue_init(q);
+ if (ret)
+ return ret;
+ saa7134_pgtable_alloc(dev->pci, &dev->video_q.pt);
+
+ q = &dev->vbi_vbq;
+ q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ /* Don't add VB2_USERPTR, see comment above */
+ q->io_modes = VB2_MMAP | VB2_READ;
+ if (saa7134_userptr)
+ q->io_modes |= VB2_USERPTR;
+ q->drv_priv = &dev->vbi_q;
+ q->ops = &saa7134_vbi_qops;
+ q->gfp_flags = GFP_DMA32;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->buf_struct_size = sizeof(struct saa7134_buf);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &dev->lock;
+ ret = vb2_queue_init(q);
+ if (ret)
+ return ret;
+ saa7134_pgtable_alloc(dev->pci, &dev->vbi_q.pt);
return 0;
}
@@ -2273,8 +2141,10 @@ int saa7134_video_init1(struct saa7134_dev *dev)
void saa7134_video_fini(struct saa7134_dev *dev)
{
/* free stuff */
- saa7134_pgtable_free(dev->pci, &dev->pt_cap);
- saa7134_pgtable_free(dev->pci, &dev->pt_vbi);
+ vb2_queue_release(&dev->video_vbq);
+ saa7134_pgtable_free(dev->pci, &dev->video_q.pt);
+ vb2_queue_release(&dev->vbi_vbq);
+ saa7134_pgtable_free(dev->pci, &dev->vbi_q.pt);
v4l2_ctrl_handler_free(&dev->ctrl_handler);
if (card_has_radio(dev))
v4l2_ctrl_handler_free(&dev->radio_ctrl_handler);
@@ -2367,8 +2237,7 @@ void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
spin_lock(&dev->slock);
if (dev->video_q.curr) {
- dev->video_fieldcount++;
- field = dev->video_q.curr->vb.field;
+ field = dev->field;
if (V4L2_FIELD_HAS_BOTH(field)) {
/* make sure we have seen both fields */
if ((status & 0x10) == 0x00) {
@@ -2384,18 +2253,10 @@ void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status)
if ((status & 0x10) != 0x00)
goto done;
}
- dev->video_q.curr->vb.field_count = dev->video_fieldcount;
- saa7134_buffer_finish(dev,&dev->video_q,VIDEOBUF_DONE);
+ saa7134_buffer_finish(dev, &dev->video_q, VB2_BUF_STATE_DONE);
}
- saa7134_buffer_next(dev,&dev->video_q);
+ saa7134_buffer_next(dev, &dev->video_q);
done:
spin_unlock(&dev->slock);
}
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
index 2474e848f2c0..e47edd4b57ce 100644
--- a/drivers/media/pci/saa7134/saa7134.h
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -41,11 +41,11 @@
#include <media/tuner.h>
#include <media/rc-core.h>
#include <media/ir-kbd-i2c.h>
-#include <media/videobuf-dma-sg.h>
+#include <media/videobuf2-dma-sg.h>
#include <sound/core.h>
#include <sound/pcm.h>
#if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB)
-#include <media/videobuf-dvb.h>
+#include <media/videobuf2-dvb.h>
#endif
#include "tda8290.h"
@@ -453,17 +453,15 @@ struct saa7134_thread {
/* buffer for one video/vbi/ts frame */
struct saa7134_buf {
/* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
+ struct vb2_buffer vb2;
/* saa7134 specific */
- struct saa7134_format *fmt;
unsigned int top_seen;
int (*activate)(struct saa7134_dev *dev,
struct saa7134_buf *buf,
struct saa7134_buf *next);
- /* page tables */
- struct saa7134_pgtable *pt;
+ struct list_head entry;
};
struct saa7134_dmaqueue {
@@ -472,13 +470,8 @@ struct saa7134_dmaqueue {
struct list_head queue;
struct timer_list timeout;
unsigned int need_two;
-};
-
-/* video filehandle status */
-struct saa7134_fh {
- struct v4l2_fh fh;
- bool is_empress;
- unsigned int resources;
+ unsigned int seq_nr;
+ struct saa7134_pgtable pt;
};
/* dmasound dsp status */
@@ -504,7 +497,10 @@ struct saa7134_dmasound {
unsigned int blksize;
unsigned int bufsize;
struct saa7134_pgtable pt;
- struct videobuf_dmabuf dma;
+ void *vaddr;
+ struct scatterlist *sglist;
+ int sglen;
+ int nr_pages;
unsigned int dma_blk;
unsigned int read_offset;
unsigned int read_count;
@@ -515,7 +511,6 @@ struct saa7134_dmasound {
/* ts/mpeg status */
struct saa7134_ts {
/* TS capture */
- struct saa7134_pgtable pt_ts;
int nr_packets;
int nr_bufs;
};
@@ -584,21 +579,35 @@ struct saa7134_dev {
struct v4l2_window win;
struct v4l2_clip clips[8];
unsigned int nclips;
+ struct v4l2_fh *overlay_owner;
/* video+ts+vbi capture */
struct saa7134_dmaqueue video_q;
- struct videobuf_queue cap;
- struct saa7134_pgtable pt_cap;
+ struct vb2_queue video_vbq;
struct saa7134_dmaqueue vbi_q;
- struct videobuf_queue vbi;
- struct saa7134_pgtable pt_vbi;
- unsigned int video_fieldcount;
- unsigned int vbi_fieldcount;
+ struct vb2_queue vbi_vbq;
+ enum v4l2_field field;
struct saa7134_format *fmt;
unsigned int width, height;
+ unsigned int vbi_hlen, vbi_vlen;
struct pm_qos_request qos_request;
+ /* SAA7134_MPEG_* */
+ struct saa7134_ts ts;
+ struct saa7134_dmaqueue ts_q;
+ enum v4l2_field ts_field;
+ int ts_started;
+ struct saa7134_mpeg_ops *mops;
+
+ /* SAA7134_MPEG_EMPRESS only */
+ struct video_device *empress_dev;
+ struct v4l2_subdev *empress_sd;
+ struct vb2_queue empress_vbq;
+ struct work_struct empress_workqueue;
+ int empress_started;
+ struct v4l2_ctrl_handler empress_ctrl_handler;
+
/* various v4l controls */
struct saa7134_tvnorm *tvnorm; /* video */
struct saa7134_tvaudio *tvaudio;
@@ -635,23 +644,9 @@ struct saa7134_dev {
/* I2C keyboard data */
struct IR_i2c_init_data init_data;
- /* SAA7134_MPEG_* */
- struct saa7134_ts ts;
- struct saa7134_dmaqueue ts_q;
- int ts_started;
- struct saa7134_mpeg_ops *mops;
-
- /* SAA7134_MPEG_EMPRESS only */
- struct video_device *empress_dev;
- struct v4l2_subdev *empress_sd;
- struct videobuf_queue empress_tsq;
- struct work_struct empress_workqueue;
- int empress_started;
- struct v4l2_ctrl_handler empress_ctrl_handler;
-
#if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB)
/* SAA7134_MPEG_DVB only */
- struct videobuf_dvb_frontends frontends;
+ struct vb2_dvb_frontends frontends;
int (*original_demod_sleep)(struct dvb_frontend *fe);
int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg);
@@ -705,14 +700,12 @@ struct saa7134_dev {
_rc; \
})
-static inline int res_check(struct saa7134_fh *fh, unsigned int bit)
+static inline bool is_empress(struct file *file)
{
- return fh->resources & bit;
-}
+ struct video_device *vdev = video_devdata(file);
+ struct saa7134_dev *dev = video_get_drvdata(vdev);
-static inline int res_locked(struct saa7134_dev *dev, unsigned int bit)
-{
- return dev->resources & bit;
+ return vdev->queue == &dev->empress_vbq;
}
/* ----------------------------------------------------------- */
@@ -721,6 +714,7 @@ static inline int res_locked(struct saa7134_dev *dev, unsigned int bit)
extern struct list_head saa7134_devlist;
extern struct mutex saa7134_devlist_lock;
extern int saa7134_no_overlay;
+extern bool saa7134_userptr;
void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value);
@@ -743,7 +737,7 @@ void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q,
unsigned int state);
void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
void saa7134_buffer_timeout(unsigned long data);
-void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf);
+void saa7134_stop_streaming(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
int saa7134_set_dmabits(struct saa7134_dev *dev);
@@ -777,8 +771,13 @@ extern unsigned int video_debug;
extern struct video_device saa7134_video_template;
extern struct video_device saa7134_radio_template;
+void saa7134_vb2_buffer_queue(struct vb2_buffer *vb);
+int saa7134_vb2_start_streaming(struct vb2_queue *vq, unsigned int count);
+void saa7134_vb2_stop_streaming(struct vb2_queue *vq);
+
int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id);
int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id);
+int saa7134_querystd(struct file *file, void *priv, v4l2_std_id *std);
int saa7134_enum_input(struct file *file, void *priv, struct v4l2_input *i);
int saa7134_g_input(struct file *file, void *priv, unsigned int *i);
int saa7134_s_input(struct file *file, void *priv, unsigned int i);
@@ -792,16 +791,6 @@ int saa7134_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *f);
int saa7134_s_frequency(struct file *file, void *priv,
const struct v4l2_frequency *f);
-int saa7134_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p);
-int saa7134_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *b);
-int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b);
-int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b);
-int saa7134_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type);
-int saa7134_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type);
int saa7134_videoport_init(struct saa7134_dev *dev);
void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
@@ -818,7 +807,16 @@ void saa7134_video_fini(struct saa7134_dev *dev);
#define TS_PACKET_SIZE 188 /* TS packets 188 bytes */
-extern struct videobuf_queue_ops saa7134_ts_qops;
+int saa7134_ts_buffer_init(struct vb2_buffer *vb2);
+int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2);
+void saa7134_ts_buffer_finish(struct vb2_buffer *vb2);
+int saa7134_ts_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[]);
+int saa7134_ts_start_streaming(struct vb2_queue *vq, unsigned int count);
+void saa7134_ts_stop_streaming(struct vb2_queue *vq);
+
+extern struct vb2_ops saa7134_ts_qops;
int saa7134_ts_init1(struct saa7134_dev *dev);
int saa7134_ts_fini(struct saa7134_dev *dev);
@@ -835,7 +833,7 @@ int saa7134_ts_stop(struct saa7134_dev *dev);
/* ----------------------------------------------------------- */
/* saa7134-vbi.c */
-extern struct videobuf_queue_ops saa7134_vbi_qops;
+extern struct vb2_ops saa7134_vbi_qops;
extern struct video_device saa7134_vbi_template;
int saa7134_vbi_init1(struct saa7134_dev *dev);
diff --git a/drivers/media/pci/saa7146/mxb.c b/drivers/media/pci/saa7146/mxb.c
index 33abe332d175..c4c8fce8f2b4 100644
--- a/drivers/media/pci/saa7146/mxb.c
+++ b/drivers/media/pci/saa7146/mxb.c
@@ -357,7 +357,7 @@ static int mxb_init_done(struct saa7146_dev* dev)
tea6420_route(mxb, 6);
/* select video mode in saa7111a */
- saa7111a_call(mxb, core, s_std, std);
+ saa7111a_call(mxb, video, s_std, std);
/* select tuner-output on saa7111a */
i = 0;
@@ -379,8 +379,8 @@ static int mxb_init_done(struct saa7146_dev* dev)
/* These two gpio calls set the GPIO pins that control the tda9820 */
saa7146_write(dev, GPIO_CTRL, 0x00404050);
saa7111a_call(mxb, core, s_gpio, 1);
- saa7111a_call(mxb, core, s_std, std);
- tuner_call(mxb, core, s_std, std);
+ saa7111a_call(mxb, video, s_std, std);
+ tuner_call(mxb, video, s_std, std);
/* switch to tuner-channel on tea6415c */
tea6415c_call(mxb, video, s_routing, 3, 17, 0);
@@ -771,9 +771,9 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa
/* These two gpio calls set the GPIO pins that control the tda9820 */
saa7146_write(dev, GPIO_CTRL, 0x00404050);
saa7111a_call(mxb, core, s_gpio, 0);
- saa7111a_call(mxb, core, s_std, std);
+ saa7111a_call(mxb, video, s_std, std);
if (mxb->cur_input == 0)
- tuner_call(mxb, core, s_std, std);
+ tuner_call(mxb, video, s_std, std);
} else {
v4l2_std_id std = V4L2_STD_PAL_BG;
@@ -783,9 +783,9 @@ static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *standa
/* These two gpio calls set the GPIO pins that control the tda9820 */
saa7146_write(dev, GPIO_CTRL, 0x00404050);
saa7111a_call(mxb, core, s_gpio, 1);
- saa7111a_call(mxb, core, s_std, std);
+ saa7111a_call(mxb, video, s_std, std);
if (mxb->cur_input == 0)
- tuner_call(mxb, core, s_std, std);
+ tuner_call(mxb, video, s_std, std);
}
return 0;
}
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index bb11443ed63e..d2abd3b5c2bf 100644
--- a/drivers/media/pci/sta2x11/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -357,7 +357,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
}
/* abort streaming and wait for last buffer */
-static int stop_streaming(struct vb2_queue *vq)
+static void stop_streaming(struct vb2_queue *vq)
{
struct sta2x11_vip *vip = vb2_get_drv_priv(vq);
struct vip_buffer *vip_buf, *node;
@@ -374,7 +374,6 @@ static int stop_streaming(struct vb2_queue *vq)
list_del(&vip_buf->list);
}
spin_unlock(&vip->lock);
- return 0;
}
static struct vb2_ops vip_video_qops = {
@@ -445,7 +444,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std)
int status;
if (V4L2_STD_ALL == std) {
- v4l2_subdev_call(vip->decoder, core, s_std, std);
+ v4l2_subdev_call(vip->decoder, video, s_std, std);
ssleep(2);
v4l2_subdev_call(vip->decoder, video, querystd, &newstd);
v4l2_subdev_call(vip->decoder, video, g_input_status, &status);
@@ -468,7 +467,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std)
vip->format = formats_50[0];
}
- return v4l2_subdev_call(vip->decoder, core, s_std, std);
+ return v4l2_subdev_call(vip->decoder, video, s_std, std);
}
/**
diff --git a/drivers/media/pci/ttpci/av7110_av.c b/drivers/media/pci/ttpci/av7110_av.c
index 301029ca4535..9544cfc06601 100644
--- a/drivers/media/pci/ttpci/av7110_av.c
+++ b/drivers/media/pci/ttpci/av7110_av.c
@@ -958,8 +958,10 @@ static unsigned int dvb_video_poll(struct file *file, poll_table *wait)
if (av7110->playing) {
if (FREE_COND)
mask |= (POLLOUT | POLLWRNORM);
- } else /* if not playing: may play if asked for */
- mask |= (POLLOUT | POLLWRNORM);
+ } else {
+ /* if not playing: may play if asked for */
+ mask |= (POLLOUT | POLLWRNORM);
+ }
}
return mask;
diff --git a/drivers/media/pci/zoran/zoran_device.c b/drivers/media/pci/zoran/zoran_device.c
index 519164c572c8..bf34b93f23ee 100644
--- a/drivers/media/pci/zoran/zoran_device.c
+++ b/drivers/media/pci/zoran/zoran_device.c
@@ -1572,7 +1572,7 @@ zoran_init_hardware (struct zoran *zr)
}
decoder_call(zr, core, init, 0);
- decoder_call(zr, core, s_std, zr->norm);
+ decoder_call(zr, video, s_std, zr->norm);
decoder_call(zr, video, s_routing,
zr->card.input[zr->input].muxsel, 0, 0);
diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c
index e7e9840c6c35..099d5fbebb7c 100644
--- a/drivers/media/pci/zoran/zoran_driver.c
+++ b/drivers/media/pci/zoran/zoran_driver.c
@@ -1469,7 +1469,7 @@ zoran_set_norm (struct zoran *zr,
if (on)
zr36057_overlay(zr, 0);
- decoder_call(zr, core, s_std, norm);
+ decoder_call(zr, video, s_std, norm);
encoder_call(zr, video, s_std_output, norm);
if (on)
diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c
index 200bec91182e..16e4b1c525c4 100644
--- a/drivers/media/platform/blackfin/bfin_capture.c
+++ b/drivers/media/platform/blackfin/bfin_capture.c
@@ -427,15 +427,12 @@ static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count)
return 0;
}
-static int bcap_stop_streaming(struct vb2_queue *vq)
+static void bcap_stop_streaming(struct vb2_queue *vq)
{
struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
struct ppi_if *ppi = bcap_dev->ppi;
int ret;
- if (!vb2_is_streaming(vq))
- return 0;
-
bcap_dev->stop = true;
wait_for_completion(&bcap_dev->comp);
ppi->ops->stop(ppi);
@@ -452,7 +449,6 @@ static int bcap_stop_streaming(struct vb2_queue *vq)
list_del(&bcap_dev->cur_frm->list);
vb2_buffer_done(&bcap_dev->cur_frm->vb, VB2_BUF_STATE_ERROR);
}
- return 0;
}
static struct vb2_ops bcap_video_qops = {
@@ -635,7 +631,7 @@ static int bcap_s_std(struct file *file, void *priv, v4l2_std_id std)
if (vb2_is_busy(&bcap_dev->buffer_queue))
return -EBUSY;
- ret = v4l2_subdev_call(bcap_dev->sd, core, s_std, std);
+ ret = v4l2_subdev_call(bcap_dev->sd, video, s_std, std);
if (ret < 0)
return ret;
@@ -648,7 +644,9 @@ static int bcap_enum_dv_timings(struct file *file, void *priv,
{
struct bcap_device *bcap_dev = video_drvdata(file);
- return v4l2_subdev_call(bcap_dev->sd, video,
+ timings->pad = 0;
+
+ return v4l2_subdev_call(bcap_dev->sd, pad,
enum_dv_timings, timings);
}
@@ -1069,7 +1067,7 @@ static int bcap_probe(struct platform_device *pdev)
/* now we can probe the default state */
if (config->inputs[0].capabilities & V4L2_IN_CAP_STD) {
v4l2_std_id std;
- ret = v4l2_subdev_call(bcap_dev->sd, core, g_std, &std);
+ ret = v4l2_subdev_call(bcap_dev->sd, video, g_std, &std);
if (ret) {
v4l2_err(&bcap_dev->v4l2_dev,
"Unable to get std\n");
diff --git a/drivers/media/platform/coda.c b/drivers/media/platform/coda.c
index 3e5199ee5d25..b1783791d426 100644
--- a/drivers/media/platform/coda.c
+++ b/drivers/media/platform/coda.c
@@ -2269,7 +2269,7 @@ out:
return ret;
}
-static int coda_stop_streaming(struct vb2_queue *q)
+static void coda_stop_streaming(struct vb2_queue *q)
{
struct coda_ctx *ctx = vb2_get_drv_priv(q);
struct coda_dev *dev = ctx->dev;
@@ -2295,8 +2295,6 @@ static int coda_stop_streaming(struct vb2_queue *q)
ctx->bitstream.vaddr, ctx->bitstream.size);
ctx->runcounter = 0;
}
-
- return 0;
}
static struct vb2_ops coda_qops = {
@@ -3235,7 +3233,7 @@ static int coda_probe(struct platform_device *pdev)
}
if (devm_request_threaded_irq(&pdev->dev, irq, NULL, coda_irq_handler,
- IRQF_ONESHOT, CODA_NAME, dev) < 0) {
+ IRQF_ONESHOT, dev_name(&pdev->dev), dev) < 0) {
dev_err(&pdev->dev, "failed to request irq\n");
return -ENOENT;
}
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c
index 656708252962..bf5eff99452b 100644
--- a/drivers/media/platform/davinci/vpbe_display.c
+++ b/drivers/media/platform/davinci/vpbe_display.c
@@ -355,8 +355,17 @@ static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count)
/* Set parameters in OSD and VENC */
ret = vpbe_set_osd_display_params(fh->disp_dev, layer);
- if (ret < 0)
+ if (ret < 0) {
+ struct vpbe_disp_buffer *buf, *tmp;
+
+ vb2_buffer_done(&layer->cur_frm->vb, VB2_BUF_STATE_QUEUED);
+ list_for_each_entry_safe(buf, tmp, &layer->dma_queue, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+ }
+
return ret;
+ }
/*
* if request format is yuv420 semiplanar, need to
@@ -368,7 +377,7 @@ static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count)
return ret;
}
-static int vpbe_stop_streaming(struct vb2_queue *vq)
+static void vpbe_stop_streaming(struct vb2_queue *vq)
{
struct vpbe_fh *fh = vb2_get_drv_priv(vq);
struct vpbe_layer *layer = fh->layer;
@@ -376,7 +385,7 @@ static int vpbe_stop_streaming(struct vb2_queue *vq)
unsigned long flags;
if (!vb2_is_streaming(vq))
- return 0;
+ return;
/* release all active buffers */
spin_lock_irqsave(&disp->dma_queue_lock, flags);
@@ -398,7 +407,6 @@ static int vpbe_stop_streaming(struct vb2_queue *vq)
vb2_buffer_done(&layer->next_frm->vb, VB2_BUF_STATE_ERROR);
}
spin_unlock_irqrestore(&disp->dma_queue_lock, flags);
- return 0;
}
static struct vb2_ops video_qops = {
@@ -680,29 +688,6 @@ static int vpbe_try_format(struct vpbe_display *disp_dev,
return 0;
}
-static int vpbe_display_g_priority(struct file *file, void *priv,
- enum v4l2_priority *p)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
-
- *p = v4l2_prio_max(&layer->prio);
-
- return 0;
-}
-
-static int vpbe_display_s_priority(struct file *file, void *priv,
- enum v4l2_priority p)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- int ret;
-
- ret = v4l2_prio_change(&layer->prio, &fh->prio, p);
-
- return ret;
-}
-
static int vpbe_display_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
@@ -1492,6 +1477,7 @@ static int vpbe_display_open(struct file *file)
{
struct vpbe_fh *fh = NULL;
struct vpbe_layer *layer = video_drvdata(file);
+ struct video_device *vdev = video_devdata(file);
struct vpbe_display *disp_dev = layer->disp_dev;
struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
struct osd_state *osd_device = disp_dev->osd_device;
@@ -1504,6 +1490,7 @@ static int vpbe_display_open(struct file *file)
"unable to allocate memory for file handle object\n");
return -ENOMEM;
}
+ v4l2_fh_init(&fh->fh, vdev);
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
"vpbe display open plane = %d\n",
layer->device_id);
@@ -1532,9 +1519,7 @@ static int vpbe_display_open(struct file *file)
layer->usrs++;
/* Set io_allowed member to false */
fh->io_allowed = 0;
- /* Initialize priority of this instance to default priority */
- fh->prio = V4L2_PRIORITY_UNSET;
- v4l2_prio_open(&layer->prio, &fh->prio);
+ v4l2_fh_add(&fh->fh);
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
"vpbe display device opened successfully\n");
return 0;
@@ -1589,8 +1574,9 @@ static int vpbe_display_release(struct file *file)
osd_device->ops.release_layer(osd_device,
layer->layer_info.id);
}
- /* Close the priority */
- v4l2_prio_close(&layer->prio, fh->prio);
+
+ v4l2_fh_del(&fh->fh);
+ v4l2_fh_exit(&fh->fh);
file->private_data = NULL;
mutex_unlock(&layer->opslock);
@@ -1618,8 +1604,6 @@ static const struct v4l2_ioctl_ops vpbe_ioctl_ops = {
.vidioc_cropcap = vpbe_display_cropcap,
.vidioc_g_crop = vpbe_display_g_crop,
.vidioc_s_crop = vpbe_display_s_crop,
- .vidioc_g_priority = vpbe_display_g_priority,
- .vidioc_s_priority = vpbe_display_s_priority,
.vidioc_s_std = vpbe_display_s_std,
.vidioc_g_std = vpbe_display_g_std,
.vidioc_enum_output = vpbe_display_enum_output,
@@ -1699,8 +1683,6 @@ static int init_vpbe_layer(int i, struct vpbe_display *disp_dev,
vpbe_display_layer->layer_info.id =
((i == VPBE_DISPLAY_DEVICE_0) ? WIN_VID0 : WIN_VID1);
- /* Initialize prio member of layer object */
- v4l2_prio_init(&vpbe_display_layer->prio);
return 0;
}
@@ -1727,6 +1709,7 @@ static int register_device(struct vpbe_layer *vpbe_display_layer,
vpbe_display_layer->disp_dev = disp_dev;
/* set the driver data in platform device */
platform_set_drvdata(pdev, disp_dev);
+ set_bit(V4L2_FL_USE_FH_PRIO, &vpbe_display_layer->video_dev.flags);
video_set_drvdata(&vpbe_display_layer->video_dev,
vpbe_display_layer);
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c
index 0379cb9f9a9c..a51bda2fb637 100644
--- a/drivers/media/platform/davinci/vpfe_capture.c
+++ b/drivers/media/platform/davinci/vpfe_capture.c
@@ -498,6 +498,7 @@ unlock:
static int vpfe_open(struct file *file)
{
struct vpfe_device *vpfe_dev = video_drvdata(file);
+ struct video_device *vdev = video_devdata(file);
struct vpfe_fh *fh;
v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_open\n");
@@ -517,6 +518,7 @@ static int vpfe_open(struct file *file)
/* store pointer to fh in private_data member of file */
file->private_data = fh;
fh->vpfe_dev = vpfe_dev;
+ v4l2_fh_init(&fh->fh, vdev);
mutex_lock(&vpfe_dev->lock);
/* If decoder is not initialized. initialize it */
if (!vpfe_dev->initialized) {
@@ -529,9 +531,7 @@ static int vpfe_open(struct file *file)
vpfe_dev->usrs++;
/* Set io_allowed member to false */
fh->io_allowed = 0;
- /* Initialize priority of this instance to default priority */
- fh->prio = V4L2_PRIORITY_UNSET;
- v4l2_prio_open(&vpfe_dev->prio, &fh->prio);
+ v4l2_fh_add(&fh->fh);
mutex_unlock(&vpfe_dev->lock);
return 0;
}
@@ -740,8 +740,8 @@ static int vpfe_release(struct file *file)
/* Decrement device usrs counter */
vpfe_dev->usrs--;
- /* Close the priority */
- v4l2_prio_close(&vpfe_dev->prio, fh->prio);
+ v4l2_fh_del(&fh->fh);
+ v4l2_fh_exit(&fh->fh);
/* If this is the last file handle */
if (!vpfe_dev->usrs) {
vpfe_dev->initialized = 0;
@@ -1217,7 +1217,7 @@ static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id)
}
ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- core, s_std, std_id);
+ video, s_std, std_id);
if (ret < 0) {
v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n");
goto unlock_out;
@@ -1910,14 +1910,13 @@ static int vpfe_probe(struct platform_device *pdev)
/* Initialize field of the device objects */
vpfe_dev->numbuffers = config_params.numbuffers;
- /* Initialize prio member of device object */
- v4l2_prio_init(&vpfe_dev->prio);
/* register video device */
v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
"trying to register vpfe device.\n");
v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev,
"video_dev=%x\n", (int)&vpfe_dev->video_dev);
vpfe_dev->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vpfe_dev->video_dev->flags);
ret = video_register_device(vpfe_dev->video_dev,
VFL_TYPE_GRABBER, -1);
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index 8dea0b84a3ad..a7ed16497903 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2009 Texas Instruments Inc
+ * Copyright (C) 2014 Lad, Prabhakar <prabhakar.csengg@gmail.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
@@ -65,14 +66,26 @@ static struct vpif_config_params config_params = {
.channel_bufsize[1] = 720 * 576 * 2,
};
+#define VPIF_DRIVER_NAME "vpif_capture"
+
/* global variables */
static struct vpif_device vpif_obj = { {NULL} };
static struct device *vpif_dev;
static void vpif_calculate_offsets(struct channel_obj *ch);
static void vpif_config_addr(struct channel_obj *ch, int muxmode);
+static u8 channel_first_int[VPIF_NUMBER_OF_OBJECTS][2] = { {1, 1} };
+
+/* Is set to 1 in case of SDTV formats, 2 in case of HDTV formats. */
+static int ycmux_mode;
+
+static inline struct vpif_cap_buffer *to_vpif_buffer(struct vb2_buffer *vb)
+{
+ return container_of(vb, struct vpif_cap_buffer, vb);
+}
+
/**
- * buffer_prepare : callback function for buffer prepare
+ * vpif_buffer_prepare : callback function for buffer prepare
* @vb: ptr to vb2_buffer
*
* This is the callback function for buffer prepare when vb2_qbuf()
@@ -81,10 +94,8 @@ static void vpif_config_addr(struct channel_obj *ch, int muxmode);
*/
static int vpif_buffer_prepare(struct vb2_buffer *vb)
{
- /* Get the file handle object and channel object */
- struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
struct vb2_queue *q = vb->vb2_queue;
- struct channel_obj *ch = fh->channel;
+ struct channel_obj *ch = vb2_get_drv_priv(q);
struct common_obj *common;
unsigned long addr;
@@ -92,26 +103,22 @@ static int vpif_buffer_prepare(struct vb2_buffer *vb)
common = &ch->common[VPIF_VIDEO_INDEX];
- if (vb->state != VB2_BUF_STATE_ACTIVE &&
- vb->state != VB2_BUF_STATE_PREPARED) {
- vb2_set_plane_payload(vb, 0, common->fmt.fmt.pix.sizeimage);
- if (vb2_plane_vaddr(vb, 0) &&
- vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))
- goto exit;
- addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ vb2_set_plane_payload(vb, 0, common->fmt.fmt.pix.sizeimage);
+ if (vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))
+ return -EINVAL;
- if (q->streaming) {
- if (!IS_ALIGNED((addr + common->ytop_off), 8) ||
- !IS_ALIGNED((addr + common->ybtm_off), 8) ||
- !IS_ALIGNED((addr + common->ctop_off), 8) ||
- !IS_ALIGNED((addr + common->cbtm_off), 8))
- goto exit;
- }
+ vb->v4l2_buf.field = common->fmt.fmt.pix.field;
+
+ addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ if (!IS_ALIGNED((addr + common->ytop_off), 8) ||
+ !IS_ALIGNED((addr + common->ybtm_off), 8) ||
+ !IS_ALIGNED((addr + common->ctop_off), 8) ||
+ !IS_ALIGNED((addr + common->cbtm_off), 8)) {
+ vpif_dbg(1, debug, "offset is not aligned\n");
+ return -EINVAL;
}
+
return 0;
-exit:
- vpif_dbg(1, debug, "buffer_prepare:offset is not aligned to 8 bytes\n");
- return -EINVAL;
}
/**
@@ -131,49 +138,26 @@ static int vpif_buffer_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- /* Get the file handle object and channel object */
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
+ struct channel_obj *ch = vb2_get_drv_priv(vq);
struct common_obj *common;
- unsigned long size;
common = &ch->common[VPIF_VIDEO_INDEX];
vpif_dbg(2, debug, "vpif_buffer_setup\n");
- /* If memory type is not mmap, return */
- if (V4L2_MEMORY_MMAP == common->memory) {
- /* Calculate the size of the buffer */
- size = config_params.channel_bufsize[ch->channel_id];
- /*
- * Checking if the buffer size exceeds the available buffer
- * ycmux_mode = 0 means 1 channel mode HD and
- * ycmux_mode = 1 means 2 channels mode SD
- */
- if (ch->vpifparams.std_info.ycmux_mode == 0) {
- if (config_params.video_limit[ch->channel_id])
- while (size * *nbuffers >
- (config_params.video_limit[0]
- + config_params.video_limit[1]))
- (*nbuffers)--;
- } else {
- if (config_params.video_limit[ch->channel_id])
- while (size * *nbuffers >
- config_params.video_limit[ch->channel_id])
- (*nbuffers)--;
- }
-
- } else {
- size = common->fmt.fmt.pix.sizeimage;
- }
+ if (fmt && fmt->fmt.pix.sizeimage < common->fmt.fmt.pix.sizeimage)
+ return -EINVAL;
- if (*nbuffers < config_params.min_numbuffers)
- *nbuffers = config_params.min_numbuffers;
+ if (vq->num_buffers + *nbuffers < 3)
+ *nbuffers = 3 - vq->num_buffers;
*nplanes = 1;
- sizes[0] = size;
+ sizes[0] = fmt ? fmt->fmt.pix.sizeimage : common->fmt.fmt.pix.sizeimage;
alloc_ctxs[0] = common->alloc_ctx;
+ /* Calculate the offset for Y and C data in the buffer */
+ vpif_calculate_offsets(ch);
+
return 0;
}
@@ -183,11 +167,8 @@ static int vpif_buffer_queue_setup(struct vb2_queue *vq,
*/
static void vpif_buffer_queue(struct vb2_buffer *vb)
{
- /* Get the file handle object and channel object */
- struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
- struct channel_obj *ch = fh->channel;
- struct vpif_cap_buffer *buf = container_of(vb,
- struct vpif_cap_buffer, vb);
+ struct channel_obj *ch = vb2_get_drv_priv(vb->vb2_queue);
+ struct vpif_cap_buffer *buf = to_vpif_buffer(vb);
struct common_obj *common;
unsigned long flags;
@@ -202,102 +183,25 @@ static void vpif_buffer_queue(struct vb2_buffer *vb)
}
/**
- * vpif_buf_cleanup : Callback function to free buffer
+ * vpif_start_streaming : Starts the DMA engine for streaming
* @vb: ptr to vb2_buffer
- *
- * This function is called from the videobuf2 layer to free memory
- * allocated to the buffers
+ * @count: number of buffers
*/
-static void vpif_buf_cleanup(struct vb2_buffer *vb)
-{
- /* Get the file handle object and channel object */
- struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
- struct vpif_cap_buffer *buf = container_of(vb,
- struct vpif_cap_buffer, vb);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
- unsigned long flags;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
-
- spin_lock_irqsave(&common->irqlock, flags);
- if (vb->state == VB2_BUF_STATE_ACTIVE)
- list_del_init(&buf->list);
- spin_unlock_irqrestore(&common->irqlock, flags);
-
-}
-
-static void vpif_wait_prepare(struct vb2_queue *vq)
-{
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
- mutex_unlock(&common->lock);
-}
-
-static void vpif_wait_finish(struct vb2_queue *vq)
-{
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
- mutex_lock(&common->lock);
-}
-
-static int vpif_buffer_init(struct vb2_buffer *vb)
-{
- struct vpif_cap_buffer *buf = container_of(vb,
- struct vpif_cap_buffer, vb);
-
- INIT_LIST_HEAD(&buf->list);
-
- return 0;
-}
-
-static u8 channel_first_int[VPIF_NUMBER_OF_OBJECTS][2] =
- { {1, 1} };
-
static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct vpif_capture_config *vpif_config_data =
vpif_dev->platform_data;
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
+ struct channel_obj *ch = vb2_get_drv_priv(vq);
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
struct vpif_params *vpif = &ch->vpifparams;
- unsigned long addr = 0;
- unsigned long flags;
+ struct vpif_cap_buffer *buf, *tmp;
+ unsigned long addr, flags;
int ret;
spin_lock_irqsave(&common->irqlock, flags);
- /* Get the next frame from the buffer queue */
- common->cur_frm = common->next_frm = list_entry(common->dma_queue.next,
- struct vpif_cap_buffer, list);
- /* Remove buffer from the buffer queue */
- list_del(&common->cur_frm->list);
- spin_unlock_irqrestore(&common->irqlock, flags);
- /* Mark state of the current frame to active */
- common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
- /* Initialize field_id and started member */
+ /* Initialize field_id */
ch->field_id = 0;
- common->started = 1;
- addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
-
- /* Calculate the offset for Y and C data in the buffer */
- vpif_calculate_offsets(ch);
-
- if ((vpif->std_info.frm_fmt &&
- ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE) &&
- (common->fmt.fmt.pix.field != V4L2_FIELD_ANY))) ||
- (!vpif->std_info.frm_fmt &&
- (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {
- vpif_dbg(1, debug, "conflict in field format and std format\n");
- return -EINVAL;
- }
/* configure 1 or 2 channel mode */
if (vpif_config_data->setup_input_channel_mode) {
@@ -305,21 +209,37 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
setup_input_channel_mode(vpif->std_info.ycmux_mode);
if (ret < 0) {
vpif_dbg(1, debug, "can't set vpif channel mode\n");
- return ret;
+ goto err;
}
}
+ ret = v4l2_subdev_call(ch->sd, video, s_stream, 1);
+ if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) {
+ vpif_dbg(1, debug, "stream on failed in subdev\n");
+ goto err;
+ }
+
/* Call vpif_set_params function to set the parameters and addresses */
ret = vpif_set_video_params(vpif, ch->channel_id);
-
if (ret < 0) {
vpif_dbg(1, debug, "can't set video params\n");
- return ret;
+ goto err;
}
- common->started = ret;
+ ycmux_mode = ret;
vpif_config_addr(ch, ret);
+ /* Get the next frame from the buffer queue */
+ common->cur_frm = common->next_frm = list_entry(common->dma_queue.next,
+ struct vpif_cap_buffer, list);
+ /* Remove buffer from the buffer queue */
+ list_del(&common->cur_frm->list);
+ spin_unlock_irqrestore(&common->irqlock, flags);
+ /* Mark state of the current frame to active */
+ common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
+
+ addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
+
common->set_addr(addr + common->ytop_off,
addr + common->ybtm_off,
addr + common->ctop_off,
@@ -330,31 +250,42 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
* VPIF register
*/
channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
- if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)) {
+ if (VPIF_CHANNEL0_VIDEO == ch->channel_id) {
channel0_intr_assert();
channel0_intr_enable(1);
enable_channel0(1);
}
- if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) ||
- (common->started == 2)) {
+ if (VPIF_CHANNEL1_VIDEO == ch->channel_id ||
+ ycmux_mode == 2) {
channel1_intr_assert();
channel1_intr_enable(1);
enable_channel1(1);
}
return 0;
+
+err:
+ list_for_each_entry_safe(buf, tmp, &common->dma_queue, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+ }
+
+ return ret;
}
-/* abort streaming and wait for last buffer */
-static int vpif_stop_streaming(struct vb2_queue *vq)
+/**
+ * vpif_stop_streaming : Stop the DMA engine
+ * @vq: ptr to vb2_queue
+ *
+ * This callback stops the DMA engine and any remaining buffers
+ * in the DMA queue are released.
+ */
+static void vpif_stop_streaming(struct vb2_queue *vq)
{
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
+ struct channel_obj *ch = vb2_get_drv_priv(vq);
struct common_obj *common;
unsigned long flags;
-
- if (!vb2_is_streaming(vq))
- return 0;
+ int ret;
common = &ch->common[VPIF_VIDEO_INDEX];
@@ -363,12 +294,17 @@ static int vpif_stop_streaming(struct vb2_queue *vq)
enable_channel0(0);
channel0_intr_enable(0);
}
- if ((VPIF_CHANNEL1_VIDEO == ch->channel_id) ||
- (2 == common->started)) {
+ if (VPIF_CHANNEL1_VIDEO == ch->channel_id ||
+ ycmux_mode == 2) {
enable_channel1(0);
channel1_intr_enable(0);
}
- common->started = 0;
+
+ ycmux_mode = 0;
+
+ ret = v4l2_subdev_call(ch->sd, video, s_stream, 0);
+ if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV)
+ vpif_dbg(1, debug, "stream off failed in subdev\n");
/* release all active buffers */
spin_lock_irqsave(&common->irqlock, flags);
@@ -390,19 +326,13 @@ static int vpif_stop_streaming(struct vb2_queue *vq)
vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR);
}
spin_unlock_irqrestore(&common->irqlock, flags);
-
- return 0;
}
static struct vb2_ops video_qops = {
.queue_setup = vpif_buffer_queue_setup,
- .wait_prepare = vpif_wait_prepare,
- .wait_finish = vpif_wait_finish,
- .buf_init = vpif_buffer_init,
.buf_prepare = vpif_buffer_prepare,
.start_streaming = vpif_start_streaming,
.stop_streaming = vpif_stop_streaming,
- .buf_cleanup = vpif_buf_cleanup,
.buf_queue = vpif_buffer_queue,
};
@@ -479,9 +409,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
for (i = 0; i < VPIF_NUMBER_OF_OBJECTS; i++) {
common = &ch->common[i];
/* skip If streaming is not started in this channel */
- if (0 == common->started)
- continue;
-
/* Check the field format */
if (1 == ch->vpifparams.std_info.frm_fmt) {
/* Progressive mode */
@@ -683,11 +610,6 @@ static void vpif_config_format(struct channel_obj *ch)
vpif_dbg(2, debug, "vpif_config_format\n");
common->fmt.fmt.pix.field = V4L2_FIELD_ANY;
- if (config_params.numbuffers[ch->channel_id] == 0)
- common->memory = V4L2_MEMORY_USERPTR;
- else
- common->memory = V4L2_MEMORY_MMAP;
-
common->fmt.fmt.pix.sizeimage
= config_params.channel_bufsize[ch->channel_id];
@@ -837,415 +759,6 @@ static void vpif_config_addr(struct channel_obj *ch, int muxmode)
}
/**
- * vpif_mmap : It is used to map kernel space buffers into user spaces
- * @filep: file pointer
- * @vma: ptr to vm_area_struct
- */
-static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
-{
- /* Get the channel object and file handle object */
- struct vpif_fh *fh = filep->private_data;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
- int ret;
-
- vpif_dbg(2, debug, "vpif_mmap\n");
-
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
- ret = vb2_mmap(&common->buffer_queue, vma);
- mutex_unlock(&common->lock);
- return ret;
-}
-
-/**
- * vpif_poll: It is used for select/poll system call
- * @filep: file pointer
- * @wait: poll table to wait
- */
-static unsigned int vpif_poll(struct file *filep, poll_table * wait)
-{
- struct vpif_fh *fh = filep->private_data;
- struct channel_obj *channel = fh->channel;
- struct common_obj *common = &(channel->common[VPIF_VIDEO_INDEX]);
- unsigned int res = 0;
-
- vpif_dbg(2, debug, "vpif_poll\n");
-
- if (common->started) {
- mutex_lock(&common->lock);
- res = vb2_poll(&common->buffer_queue, filep, wait);
- mutex_unlock(&common->lock);
- }
- return res;
-}
-
-/**
- * vpif_open : vpif open handler
- * @filep: file ptr
- *
- * It creates object of file handle structure and stores it in private_data
- * member of filepointer
- */
-static int vpif_open(struct file *filep)
-{
- struct video_device *vdev = video_devdata(filep);
- struct common_obj *common;
- struct video_obj *vid_ch;
- struct channel_obj *ch;
- struct vpif_fh *fh;
-
- vpif_dbg(2, debug, "vpif_open\n");
-
- ch = video_get_drvdata(vdev);
-
- vid_ch = &ch->video;
- common = &ch->common[VPIF_VIDEO_INDEX];
-
- /* Allocate memory for the file handle object */
- fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);
- if (NULL == fh) {
- vpif_err("unable to allocate memory for file handle object\n");
- return -ENOMEM;
- }
-
- if (mutex_lock_interruptible(&common->lock)) {
- kfree(fh);
- return -ERESTARTSYS;
- }
- /* store pointer to fh in private_data member of filep */
- filep->private_data = fh;
- fh->channel = ch;
- fh->initialized = 0;
- /* If decoder is not initialized. initialize it */
- if (!ch->initialized) {
- fh->initialized = 1;
- ch->initialized = 1;
- memset(&(ch->vpifparams), 0, sizeof(struct vpif_params));
- }
- /* Increment channel usrs counter */
- ch->usrs++;
- /* Set io_allowed member to false */
- fh->io_allowed[VPIF_VIDEO_INDEX] = 0;
- /* Initialize priority of this instance to default priority */
- fh->prio = V4L2_PRIORITY_UNSET;
- v4l2_prio_open(&ch->prio, &fh->prio);
- mutex_unlock(&common->lock);
- return 0;
-}
-
-/**
- * vpif_release : function to clean up file close
- * @filep: file pointer
- *
- * This function deletes buffer queue, frees the buffers and the vpif file
- * handle
- */
-static int vpif_release(struct file *filep)
-{
- struct vpif_fh *fh = filep->private_data;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
-
- vpif_dbg(2, debug, "vpif_release\n");
-
- common = &ch->common[VPIF_VIDEO_INDEX];
-
- mutex_lock(&common->lock);
- /* if this instance is doing IO */
- if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
- /* Reset io_usrs member of channel object */
- common->io_usrs = 0;
- /* Free buffers allocated */
- vb2_queue_release(&common->buffer_queue);
- vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
- }
-
- /* Decrement channel usrs counter */
- ch->usrs--;
-
- /* Close the priority */
- v4l2_prio_close(&ch->prio, fh->prio);
-
- if (fh->initialized)
- ch->initialized = 0;
-
- mutex_unlock(&common->lock);
- filep->private_data = NULL;
- kfree(fh);
- return 0;
-}
-
-/**
- * vpif_reqbufs() - request buffer handler
- * @file: file ptr
- * @priv: file handle
- * @reqbuf: request buffer structure ptr
- */
-static int vpif_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *reqbuf)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
- u8 index = 0;
- struct vb2_queue *q;
- int ret;
-
- vpif_dbg(2, debug, "vpif_reqbufs\n");
-
- /**
- * This file handle has not initialized the channel,
- * It is not allowed to do settings
- */
- if ((VPIF_CHANNEL0_VIDEO == ch->channel_id)
- || (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
- if (!fh->initialized) {
- vpif_dbg(1, debug, "Channel Busy\n");
- return -EBUSY;
- }
- }
-
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != reqbuf->type || !vpif_dev)
- return -EINVAL;
-
- index = VPIF_VIDEO_INDEX;
-
- common = &ch->common[index];
-
- if (0 != common->io_usrs)
- return -EBUSY;
-
- /* Initialize videobuf2 queue as per the buffer type */
- common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev);
- if (IS_ERR(common->alloc_ctx)) {
- vpif_err("Failed to get the context\n");
- return PTR_ERR(common->alloc_ctx);
- }
- q = &common->buffer_queue;
- q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- q->io_modes = VB2_MMAP | VB2_USERPTR;
- q->drv_priv = fh;
- q->ops = &video_qops;
- q->mem_ops = &vb2_dma_contig_memops;
- q->buf_struct_size = sizeof(struct vpif_cap_buffer);
- q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 1;
-
- ret = vb2_queue_init(q);
- if (ret) {
- vpif_err("vpif_capture: vb2_queue_init() failed\n");
- vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
- return ret;
- }
- /* Set io allowed member of file handle to TRUE */
- fh->io_allowed[index] = 1;
- /* Increment io usrs member of channel object to 1 */
- common->io_usrs = 1;
- /* Store type of memory requested in channel object */
- common->memory = reqbuf->memory;
- INIT_LIST_HEAD(&common->dma_queue);
-
- /* Allocate buffers */
- return vb2_reqbufs(&common->buffer_queue, reqbuf);
-}
-
-/**
- * vpif_querybuf() - query buffer handler
- * @file: file ptr
- * @priv: file handle
- * @buf: v4l2 buffer structure ptr
- */
-static int vpif_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- vpif_dbg(2, debug, "vpif_querybuf\n");
-
- if (common->fmt.type != buf->type)
- return -EINVAL;
-
- if (common->memory != V4L2_MEMORY_MMAP) {
- vpif_dbg(1, debug, "Invalid memory\n");
- return -EINVAL;
- }
-
- return vb2_querybuf(&common->buffer_queue, buf);
-}
-
-/**
- * vpif_qbuf() - query buffer handler
- * @file: file ptr
- * @priv: file handle
- * @buf: v4l2 buffer structure ptr
- */
-static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
-
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct v4l2_buffer tbuf = *buf;
-
- vpif_dbg(2, debug, "vpif_qbuf\n");
-
- if (common->fmt.type != tbuf.type) {
- vpif_err("invalid buffer type\n");
- return -EINVAL;
- }
-
- if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
- vpif_err("fh io not allowed\n");
- return -EACCES;
- }
-
- return vb2_qbuf(&common->buffer_queue, buf);
-}
-
-/**
- * vpif_dqbuf() - query buffer handler
- * @file: file ptr
- * @priv: file handle
- * @buf: v4l2 buffer structure ptr
- */
-static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- vpif_dbg(2, debug, "vpif_dqbuf\n");
-
- return vb2_dqbuf(&common->buffer_queue, buf,
- (file->f_flags & O_NONBLOCK));
-}
-
-/**
- * vpif_streamon() - streamon handler
- * @file: file ptr
- * @priv: file handle
- * @buftype: v4l2 buffer type
- */
-static int vpif_streamon(struct file *file, void *priv,
- enum v4l2_buf_type buftype)
-{
-
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id];
- struct vpif_params *vpif;
- int ret = 0;
-
- vpif_dbg(2, debug, "vpif_streamon\n");
-
- vpif = &ch->vpifparams;
-
- if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- vpif_dbg(1, debug, "buffer type not supported\n");
- return -EINVAL;
- }
-
- /* If file handle is not allowed IO, return error */
- if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
- vpif_dbg(1, debug, "io not allowed\n");
- return -EACCES;
- }
-
- /* If Streaming is already started, return error */
- if (common->started) {
- vpif_dbg(1, debug, "channel->started\n");
- return -EBUSY;
- }
-
- if ((ch->channel_id == VPIF_CHANNEL0_VIDEO &&
- oth_ch->common[VPIF_VIDEO_INDEX].started &&
- vpif->std_info.ycmux_mode == 0) ||
- ((ch->channel_id == VPIF_CHANNEL1_VIDEO) &&
- (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) {
- vpif_dbg(1, debug, "other channel is being used\n");
- return -EBUSY;
- }
-
- ret = vpif_check_format(ch, &common->fmt.fmt.pix, 0);
- if (ret)
- return ret;
-
- /* Enable streamon on the sub device */
- ret = v4l2_subdev_call(ch->sd, video, s_stream, 1);
-
- if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) {
- vpif_dbg(1, debug, "stream on failed in subdev\n");
- return ret;
- }
-
- /* Call vb2_streamon to start streaming in videobuf2 */
- ret = vb2_streamon(&common->buffer_queue, buftype);
- if (ret) {
- vpif_dbg(1, debug, "vb2_streamon\n");
- return ret;
- }
-
- return ret;
-}
-
-/**
- * vpif_streamoff() - streamoff handler
- * @file: file ptr
- * @priv: file handle
- * @buftype: v4l2 buffer type
- */
-static int vpif_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type buftype)
-{
-
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- int ret;
-
- vpif_dbg(2, debug, "vpif_streamoff\n");
-
- if (buftype != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- vpif_dbg(1, debug, "buffer type not supported\n");
- return -EINVAL;
- }
-
- /* If io is allowed for this file handle, return error */
- if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
- vpif_dbg(1, debug, "io not allowed\n");
- return -EACCES;
- }
-
- /* If streaming is not started, return error */
- if (!common->started) {
- vpif_dbg(1, debug, "channel->started\n");
- return -EINVAL;
- }
-
- /* disable channel */
- if (VPIF_CHANNEL0_VIDEO == ch->channel_id) {
- enable_channel0(0);
- channel0_intr_enable(0);
- } else {
- enable_channel1(0);
- channel1_intr_enable(0);
- }
-
- common->started = 0;
-
- ret = v4l2_subdev_call(ch->sd, video, s_stream, 0);
-
- if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV)
- vpif_dbg(1, debug, "stream off failed in subdev\n");
-
- return vb2_streamoff(&common->buffer_queue, buftype);
-}
-
-/**
* vpif_input_to_subdev() - Maps input to sub device
* @vpif_cfg - global config ptr
* @chan_cfg - channel config ptr
@@ -1348,8 +861,8 @@ static int vpif_set_input(
*/
static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
int ret = 0;
vpif_dbg(2, debug, "vpif_querystd\n");
@@ -1375,11 +888,22 @@ static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
*/
static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct vpif_capture_config *config = vpif_dev->platform_data;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
+ struct vpif_capture_chan_config *chan_cfg;
+ struct v4l2_input input;
vpif_dbg(2, debug, "vpif_g_std\n");
+ if (config->chan_config[ch->channel_id].inputs == NULL)
+ return -ENODATA;
+
+ chan_cfg = &config->chan_config[ch->channel_id];
+ input = chan_cfg->inputs[ch->input_idx].input;
+ if (input.capabilities != V4L2_IN_CAP_STD)
+ return -ENODATA;
+
*std = ch->video.stdid;
return 0;
}
@@ -1392,31 +916,26 @@ static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std)
*/
static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct vpif_capture_config *config = vpif_dev->platform_data;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- int ret = 0;
+ struct vpif_capture_chan_config *chan_cfg;
+ struct v4l2_input input;
+ int ret;
vpif_dbg(2, debug, "vpif_s_std\n");
- if (common->started) {
- vpif_err("streaming in progress\n");
- return -EBUSY;
- }
-
- if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
- (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
- if (!fh->initialized) {
- vpif_dbg(1, debug, "Channel Busy\n");
- return -EBUSY;
- }
- }
+ if (config->chan_config[ch->channel_id].inputs == NULL)
+ return -ENODATA;
- ret = v4l2_prio_check(&ch->prio, fh->prio);
- if (0 != ret)
- return ret;
+ chan_cfg = &config->chan_config[ch->channel_id];
+ input = chan_cfg->inputs[ch->input_idx].input;
+ if (input.capabilities != V4L2_IN_CAP_STD)
+ return -ENODATA;
- fh->initialized = 1;
+ if (vb2_is_busy(&common->buffer_queue))
+ return -EBUSY;
/* Call encoder subdevice function to set the standard */
ch->video.stdid = std_id;
@@ -1432,7 +951,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id)
vpif_config_format(ch);
/* set standard in the sub device */
- ret = v4l2_subdev_call(ch->sd, core, s_std, std_id);
+ ret = v4l2_subdev_call(ch->sd, video, s_std, std_id);
if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV) {
vpif_dbg(1, debug, "Failed to set standard for sub devices\n");
return ret;
@@ -1451,9 +970,9 @@ static int vpif_enum_input(struct file *file, void *priv,
{
struct vpif_capture_config *config = vpif_dev->platform_data;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
struct vpif_capture_chan_config *chan_cfg;
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
chan_cfg = &config->chan_config[ch->channel_id];
@@ -1475,8 +994,8 @@ static int vpif_enum_input(struct file *file, void *priv,
*/
static int vpif_g_input(struct file *file, void *priv, unsigned int *index)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
*index = ch->input_idx;
return 0;
@@ -1491,35 +1010,19 @@ static int vpif_g_input(struct file *file, void *priv, unsigned int *index)
static int vpif_s_input(struct file *file, void *priv, unsigned int index)
{
struct vpif_capture_config *config = vpif_dev->platform_data;
- struct vpif_capture_chan_config *chan_cfg;
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- int ret;
+ struct vpif_capture_chan_config *chan_cfg;
chan_cfg = &config->chan_config[ch->channel_id];
if (index >= chan_cfg->input_count)
return -EINVAL;
- if (common->started) {
- vpif_err("Streaming in progress\n");
+ if (vb2_is_busy(&common->buffer_queue))
return -EBUSY;
- }
-
- if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
- (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
- if (!fh->initialized) {
- vpif_dbg(1, debug, "Channel Busy\n");
- return -EBUSY;
- }
- }
-
- ret = v4l2_prio_check(&ch->prio, fh->prio);
- if (0 != ret)
- return ret;
- fh->initialized = 1;
return vpif_set_input(config, ch, index);
}
@@ -1532,8 +1035,8 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index)
static int vpif_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *fmt)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
if (fmt->index != 0) {
vpif_dbg(1, debug, "Invalid format index\n");
@@ -1562,8 +1065,8 @@ static int vpif_enum_fmt_vid_cap(struct file *file, void *priv,
static int vpif_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
return vpif_check_format(ch, pixfmt, 1);
@@ -1579,8 +1082,8 @@ static int vpif_try_fmt_vid_cap(struct file *file, void *priv,
static int vpif_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
/* Check the validity of the buffer type */
@@ -1601,33 +1104,16 @@ static int vpif_g_fmt_vid_cap(struct file *file, void *priv,
static int vpif_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
struct v4l2_pix_format *pixfmt;
int ret = 0;
vpif_dbg(2, debug, "%s\n", __func__);
- /* If streaming is started, return error */
- if (common->started) {
- vpif_dbg(1, debug, "Streaming is started\n");
+ if (vb2_is_busy(&common->buffer_queue))
return -EBUSY;
- }
-
- if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
- (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
- if (!fh->initialized) {
- vpif_dbg(1, debug, "Channel Busy\n");
- return -EBUSY;
- }
- }
-
- ret = v4l2_prio_check(&ch->prio, fh->prio);
- if (0 != ret)
- return ret;
-
- fh->initialized = 1;
pixfmt = &fmt->fmt.pix;
/* Check for valid field format */
@@ -1653,7 +1139,7 @@ static int vpif_querycap(struct file *file, void *priv,
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
- snprintf(cap->driver, sizeof(cap->driver), "%s", dev_name(vpif_dev));
+ strlcpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(vpif_dev));
strlcpy(cap->card, config->card_name, sizeof(cap->card));
@@ -1662,61 +1148,6 @@ static int vpif_querycap(struct file *file, void *priv,
}
/**
- * vpif_g_priority() - get priority handler
- * @file: file ptr
- * @priv: file handle
- * @prio: ptr to v4l2_priority structure
- */
-static int vpif_g_priority(struct file *file, void *priv,
- enum v4l2_priority *prio)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- *prio = v4l2_prio_max(&ch->prio);
-
- return 0;
-}
-
-/**
- * vpif_s_priority() - set priority handler
- * @file: file ptr
- * @priv: file handle
- * @prio: ptr to v4l2_priority structure
- */
-static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- return v4l2_prio_change(&ch->prio, &fh->prio, p);
-}
-
-/**
- * vpif_cropcap() - cropcap handler
- * @file: file ptr
- * @priv: file handle
- * @crop: ptr to v4l2_cropcap structure
- */
-static int vpif_cropcap(struct file *file, void *priv,
- struct v4l2_cropcap *crop)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != crop->type)
- return -EINVAL;
-
- crop->bounds.left = 0;
- crop->bounds.top = 0;
- crop->bounds.height = common->height;
- crop->bounds.width = common->width;
- crop->defrect = crop->bounds;
- return 0;
-}
-
-/**
* vpif_enum_dv_timings() - ENUM_DV_TIMINGS handler
* @file: file ptr
* @priv: file handle
@@ -1726,13 +1157,27 @@ static int
vpif_enum_dv_timings(struct file *file, void *priv,
struct v4l2_enum_dv_timings *timings)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct vpif_capture_config *config = vpif_dev->platform_data;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
+ struct vpif_capture_chan_config *chan_cfg;
+ struct v4l2_input input;
int ret;
- ret = v4l2_subdev_call(ch->sd, video, enum_dv_timings, timings);
+ if (config->chan_config[ch->channel_id].inputs == NULL)
+ return -ENODATA;
+
+ chan_cfg = &config->chan_config[ch->channel_id];
+ input = chan_cfg->inputs[ch->input_idx].input;
+ if (input.capabilities != V4L2_IN_CAP_DV_TIMINGS)
+ return -ENODATA;
+
+ timings->pad = 0;
+
+ ret = v4l2_subdev_call(ch->sd, pad, enum_dv_timings, timings);
if (ret == -ENOIOCTLCMD || ret == -ENODEV)
return -EINVAL;
+
return ret;
}
@@ -1746,13 +1191,25 @@ static int
vpif_query_dv_timings(struct file *file, void *priv,
struct v4l2_dv_timings *timings)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct vpif_capture_config *config = vpif_dev->platform_data;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
+ struct vpif_capture_chan_config *chan_cfg;
+ struct v4l2_input input;
int ret;
+ if (config->chan_config[ch->channel_id].inputs == NULL)
+ return -ENODATA;
+
+ chan_cfg = &config->chan_config[ch->channel_id];
+ input = chan_cfg->inputs[ch->input_idx].input;
+ if (input.capabilities != V4L2_IN_CAP_DV_TIMINGS)
+ return -ENODATA;
+
ret = v4l2_subdev_call(ch->sd, video, query_dv_timings, timings);
if (ret == -ENOIOCTLCMD || ret == -ENODEV)
return -ENODATA;
+
return ret;
}
@@ -1765,19 +1222,34 @@ vpif_query_dv_timings(struct file *file, void *priv,
static int vpif_s_dv_timings(struct file *file, void *priv,
struct v4l2_dv_timings *timings)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct vpif_capture_config *config = vpif_dev->platform_data;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
struct vpif_params *vpifparams = &ch->vpifparams;
struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
struct video_obj *vid_ch = &ch->video;
struct v4l2_bt_timings *bt = &vid_ch->dv_timings.bt;
+ struct vpif_capture_chan_config *chan_cfg;
+ struct v4l2_input input;
int ret;
+ if (config->chan_config[ch->channel_id].inputs == NULL)
+ return -ENODATA;
+
+ chan_cfg = &config->chan_config[ch->channel_id];
+ input = chan_cfg->inputs[ch->input_idx].input;
+ if (input.capabilities != V4L2_IN_CAP_DV_TIMINGS)
+ return -ENODATA;
+
if (timings->type != V4L2_DV_BT_656_1120) {
vpif_dbg(2, debug, "Timing type not defined\n");
return -EINVAL;
}
+ if (vb2_is_busy(&common->buffer_queue))
+ return -EBUSY;
+
/* Configure subdevice timings, if any */
ret = v4l2_subdev_call(ch->sd, video, s_dv_timings, timings);
if (ret == -ENOIOCTLCMD || ret == -ENODEV)
@@ -1853,9 +1325,20 @@ static int vpif_s_dv_timings(struct file *file, void *priv,
static int vpif_g_dv_timings(struct file *file, void *priv,
struct v4l2_dv_timings *timings)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct vpif_capture_config *config = vpif_dev->platform_data;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
struct video_obj *vid_ch = &ch->video;
+ struct vpif_capture_chan_config *chan_cfg;
+ struct v4l2_input input;
+
+ if (config->chan_config[ch->channel_id].inputs == NULL)
+ return -ENODATA;
+
+ chan_cfg = &config->chan_config[ch->channel_id];
+ input = chan_cfg->inputs[ch->input_idx].input;
+ if (input.capabilities != V4L2_IN_CAP_DV_TIMINGS)
+ return -ENODATA;
*timings = vid_ch->dv_timings;
@@ -1879,49 +1362,45 @@ static int vpif_log_status(struct file *filep, void *priv)
/* vpif capture ioctl operations */
static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
- .vidioc_querycap = vpif_querycap,
- .vidioc_g_priority = vpif_g_priority,
- .vidioc_s_priority = vpif_s_priority,
+ .vidioc_querycap = vpif_querycap,
.vidioc_enum_fmt_vid_cap = vpif_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = vpif_g_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vpif_g_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vpif_s_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vpif_try_fmt_vid_cap,
+
.vidioc_enum_input = vpif_enum_input,
.vidioc_s_input = vpif_s_input,
.vidioc_g_input = vpif_g_input,
- .vidioc_reqbufs = vpif_reqbufs,
- .vidioc_querybuf = vpif_querybuf,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+
.vidioc_querystd = vpif_querystd,
- .vidioc_s_std = vpif_s_std,
+ .vidioc_s_std = vpif_s_std,
.vidioc_g_std = vpif_g_std,
- .vidioc_qbuf = vpif_qbuf,
- .vidioc_dqbuf = vpif_dqbuf,
- .vidioc_streamon = vpif_streamon,
- .vidioc_streamoff = vpif_streamoff,
- .vidioc_cropcap = vpif_cropcap,
- .vidioc_enum_dv_timings = vpif_enum_dv_timings,
- .vidioc_query_dv_timings = vpif_query_dv_timings,
- .vidioc_s_dv_timings = vpif_s_dv_timings,
- .vidioc_g_dv_timings = vpif_g_dv_timings,
+
+ .vidioc_enum_dv_timings = vpif_enum_dv_timings,
+ .vidioc_query_dv_timings = vpif_query_dv_timings,
+ .vidioc_s_dv_timings = vpif_s_dv_timings,
+ .vidioc_g_dv_timings = vpif_g_dv_timings,
+
.vidioc_log_status = vpif_log_status,
};
/* vpif file operations */
static struct v4l2_file_operations vpif_fops = {
.owner = THIS_MODULE,
- .open = vpif_open,
- .release = vpif_release,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
.unlocked_ioctl = video_ioctl2,
- .mmap = vpif_mmap,
- .poll = vpif_poll
-};
-
-/* vpif video template */
-static struct video_device vpif_video_template = {
- .name = "vpif",
- .fops = &vpif_fops,
- .minor = -1,
- .ioctl_ops = &vpif_ioctl_ops,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll
};
/**
@@ -1999,7 +1478,9 @@ static int vpif_async_bound(struct v4l2_async_notifier *notifier,
static int vpif_probe_complete(void)
{
struct common_obj *common;
+ struct video_device *vdev;
struct channel_obj *ch;
+ struct vb2_queue *q;
int i, j, err, k;
for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) {
@@ -2008,17 +1489,52 @@ static int vpif_probe_complete(void)
common = &(ch->common[VPIF_VIDEO_INDEX]);
spin_lock_init(&common->irqlock);
mutex_init(&common->lock);
- ch->video_dev->lock = &common->lock;
- /* Initialize prio member of channel object */
- v4l2_prio_init(&ch->prio);
- video_set_drvdata(ch->video_dev, ch);
/* select input 0 */
err = vpif_set_input(vpif_obj.config, ch, 0);
if (err)
goto probe_out;
- err = video_register_device(ch->video_dev,
+ /* Initialize vb2 queue */
+ q = &common->buffer_queue;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ q->drv_priv = ch;
+ q->ops = &video_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->buf_struct_size = sizeof(struct vpif_cap_buffer);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_buffers_needed = 1;
+ q->lock = &common->lock;
+
+ err = vb2_queue_init(q);
+ if (err) {
+ vpif_err("vpif_capture: vb2_queue_init() failed\n");
+ goto probe_out;
+ }
+
+ common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev);
+ if (IS_ERR(common->alloc_ctx)) {
+ vpif_err("Failed to get the context\n");
+ err = PTR_ERR(common->alloc_ctx);
+ goto probe_out;
+ }
+
+ INIT_LIST_HEAD(&common->dma_queue);
+
+ /* Initialize the video_device structure */
+ vdev = ch->video_dev;
+ strlcpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name));
+ vdev->release = video_device_release;
+ vdev->fops = &vpif_fops;
+ vdev->ioctl_ops = &vpif_ioctl_ops;
+ vdev->v4l2_dev = &vpif_obj.v4l2_dev;
+ vdev->vfl_dir = VFL_DIR_RX;
+ vdev->queue = q;
+ vdev->lock = &common->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags);
+ video_set_drvdata(ch->video_dev, ch);
+ err = video_register_device(vdev,
VFL_TYPE_GRABBER, (j ? 1 : 0));
if (err)
goto probe_out;
@@ -2031,6 +1547,8 @@ probe_out:
for (k = 0; k < j; k++) {
/* Get the pointer to the channel object */
ch = vpif_obj.dev[k];
+ common = &ch->common[k];
+ vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
/* Unregister video device */
video_unregister_device(ch->video_dev);
}
@@ -2067,7 +1585,6 @@ static __init int vpif_probe(struct platform_device *pdev)
struct video_device *vfd;
struct resource *res;
int subdev_count;
- size_t size;
vpif_dev = &pdev->dev;
@@ -2085,7 +1602,7 @@ static __init int vpif_probe(struct platform_device *pdev)
while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) {
err = devm_request_irq(&pdev->dev, res->start, vpif_channel_isr,
- IRQF_SHARED, "VPIF_Capture",
+ IRQF_SHARED, VPIF_DRIVER_NAME,
(void *)(&vpif_obj.dev[res_idx]->
channel_id));
if (err) {
@@ -2109,34 +1626,10 @@ static __init int vpif_probe(struct platform_device *pdev)
goto vpif_unregister;
}
- /* Initialize field of video device */
- *vfd = vpif_video_template;
- vfd->v4l2_dev = &vpif_obj.v4l2_dev;
- vfd->release = video_device_release;
- snprintf(vfd->name, sizeof(vfd->name),
- "VPIF_Capture_DRIVER_V%s",
- VPIF_CAPTURE_VERSION);
/* Set video_dev to the video device */
ch->video_dev = vfd;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res) {
- size = resource_size(res);
- /* The resources are divided into two equal memory and when we
- * have HD output we can add them together
- */
- for (j = 0; j < VPIF_CAPTURE_MAX_DEVICES; j++) {
- ch = vpif_obj.dev[j];
- ch->channel_id = j;
- /* only enabled if second resource exists */
- config_params.video_limit[ch->channel_id] = 0;
- if (size)
- config_params.video_limit[ch->channel_id] =
- size/2;
- }
- }
-
vpif_obj.config = pdev->dev.platform_data;
subdev_count = vpif_obj.config->subdev_count;
@@ -2209,6 +1702,7 @@ vpif_unregister:
*/
static int vpif_remove(struct platform_device *device)
{
+ struct common_obj *common;
struct channel_obj *ch;
int i;
@@ -2219,6 +1713,8 @@ static int vpif_remove(struct platform_device *device)
for (i = 0; i < VPIF_CAPTURE_MAX_DEVICES; i++) {
/* Get the pointer to the channel object */
ch = vpif_obj.dev[i];
+ common = &ch->common[i];
+ vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
/* Unregister video device */
video_unregister_device(ch->video_dev);
kfree(vpif_obj.dev[i]);
@@ -2226,7 +1722,7 @@ static int vpif_remove(struct platform_device *device)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/**
* vpif_suspend: vpif device suspend
*/
@@ -2241,18 +1737,20 @@ static int vpif_suspend(struct device *dev)
/* Get the pointer to the channel object */
ch = vpif_obj.dev[i];
common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (!vb2_is_streaming(&common->buffer_queue))
+ continue;
+
mutex_lock(&common->lock);
- if (ch->usrs && common->io_usrs) {
- /* Disable channel */
- if (ch->channel_id == VPIF_CHANNEL0_VIDEO) {
- enable_channel0(0);
- channel0_intr_enable(0);
- }
- if (ch->channel_id == VPIF_CHANNEL1_VIDEO ||
- common->started == 2) {
- enable_channel1(0);
- channel1_intr_enable(0);
- }
+ /* Disable channel */
+ if (ch->channel_id == VPIF_CHANNEL0_VIDEO) {
+ enable_channel0(0);
+ channel0_intr_enable(0);
+ }
+ if (ch->channel_id == VPIF_CHANNEL1_VIDEO ||
+ ycmux_mode == 2) {
+ enable_channel1(0);
+ channel1_intr_enable(0);
}
mutex_unlock(&common->lock);
}
@@ -2273,40 +1771,35 @@ static int vpif_resume(struct device *dev)
/* Get the pointer to the channel object */
ch = vpif_obj.dev[i];
common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (!vb2_is_streaming(&common->buffer_queue))
+ continue;
+
mutex_lock(&common->lock);
- if (ch->usrs && common->io_usrs) {
- /* Disable channel */
- if (ch->channel_id == VPIF_CHANNEL0_VIDEO) {
- enable_channel0(1);
- channel0_intr_enable(1);
- }
- if (ch->channel_id == VPIF_CHANNEL1_VIDEO ||
- common->started == 2) {
- enable_channel1(1);
- channel1_intr_enable(1);
- }
+ /* Enable channel */
+ if (ch->channel_id == VPIF_CHANNEL0_VIDEO) {
+ enable_channel0(1);
+ channel0_intr_enable(1);
+ }
+ if (ch->channel_id == VPIF_CHANNEL1_VIDEO ||
+ ycmux_mode == 2) {
+ enable_channel1(1);
+ channel1_intr_enable(1);
}
mutex_unlock(&common->lock);
}
return 0;
}
-
-static const struct dev_pm_ops vpif_dev_pm_ops = {
- .suspend = vpif_suspend,
- .resume = vpif_resume,
-};
-
-#define vpif_pm_ops (&vpif_dev_pm_ops)
-#else
-#define vpif_pm_ops NULL
#endif
+static SIMPLE_DEV_PM_OPS(vpif_pm_ops, vpif_suspend, vpif_resume);
+
static __refdata struct platform_driver vpif_driver = {
.driver = {
- .name = "vpif_capture",
+ .name = VPIF_DRIVER_NAME,
.owner = THIS_MODULE,
- .pm = vpif_pm_ops,
+ .pm = &vpif_pm_ops,
},
.probe = vpif_probe,
.remove = vpif_remove,
diff --git a/drivers/media/platform/davinci/vpif_capture.h b/drivers/media/platform/davinci/vpif_capture.h
index 5a29d9a0cae1..1ee17824f484 100644
--- a/drivers/media/platform/davinci/vpif_capture.h
+++ b/drivers/media/platform/davinci/vpif_capture.h
@@ -19,8 +19,6 @@
#ifndef VPIF_CAPTURE_H
#define VPIF_CAPTURE_H
-#ifdef __KERNEL__
-
/* Header files */
#include <media/videobuf2-dma-contig.h>
#include <media/v4l2-device.h>
@@ -63,11 +61,6 @@ struct common_obj {
struct vpif_cap_buffer *cur_frm;
/* Pointer pointing to current v4l2_buffer */
struct vpif_cap_buffer *next_frm;
- /*
- * This field keeps track of type of buffer exchange mechanism
- * user has selected
- */
- enum v4l2_memory memory;
/* Used to store pixel format */
struct v4l2_format fmt;
/* Buffer queue used in video-buf */
@@ -80,10 +73,6 @@ struct common_obj {
spinlock_t irqlock;
/* lock used to access this structure */
struct mutex lock;
- /* number of users performing IO */
- u32 io_usrs;
- /* Indicates whether streaming started */
- u8 started;
/* Function pointer to set the addresses */
void (*set_addr) (unsigned long, unsigned long, unsigned long,
unsigned long);
@@ -104,10 +93,6 @@ struct common_obj {
struct channel_obj {
/* Identifies video device for this channel */
struct video_device *video_dev;
- /* Used to keep track of state of the priority */
- struct v4l2_prio_state prio;
- /* number of open instances of the channel */
- int usrs;
/* Indicates id of the field which is being displayed */
u32 field_id;
/* flag to indicate whether decoder is initialized */
@@ -126,18 +111,6 @@ struct channel_obj {
struct video_obj video;
};
-/* File handle structure */
-struct vpif_fh {
- /* pointer to channel object for opened device */
- struct channel_obj *channel;
- /* Indicates whether this file handle is doing IO */
- u8 io_allowed[VPIF_NUMBER_OF_OBJECTS];
- /* Used to keep track priority of this instance */
- enum v4l2_priority prio;
- /* Used to indicate channel is initialize or not */
- u8 initialized;
-};
-
struct vpif_device {
struct v4l2_device v4l2_dev;
struct channel_obj *dev[VPIF_CAPTURE_NUM_CHANNELS];
@@ -157,5 +130,4 @@ struct vpif_config_params {
u8 max_device_type;
};
-#endif /* End of __KERNEL__ */
#endif /* VPIF_CAPTURE_H */
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
index aed41edd0501..5bb085b19bcb 100644
--- a/drivers/media/platform/davinci/vpif_display.c
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -3,6 +3,7 @@
* Display driver for TI DaVinci VPIF
*
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2014 Lad, Prabhakar <prabhakar.csengg@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -35,129 +36,110 @@ MODULE_VERSION(VPIF_DISPLAY_VERSION);
v4l2_dbg(level, debug, &vpif_obj.v4l2_dev, fmt, ## arg)
static int debug = 1;
-static u32 ch2_numbuffers = 3;
-static u32 ch3_numbuffers = 3;
-static u32 ch2_bufsize = 1920 * 1080 * 2;
-static u32 ch3_bufsize = 720 * 576 * 2;
module_param(debug, int, 0644);
-module_param(ch2_numbuffers, uint, S_IRUGO);
-module_param(ch3_numbuffers, uint, S_IRUGO);
-module_param(ch2_bufsize, uint, S_IRUGO);
-module_param(ch3_bufsize, uint, S_IRUGO);
MODULE_PARM_DESC(debug, "Debug level 0-1");
-MODULE_PARM_DESC(ch2_numbuffers, "Channel2 buffer count (default:3)");
-MODULE_PARM_DESC(ch3_numbuffers, "Channel3 buffer count (default:3)");
-MODULE_PARM_DESC(ch2_bufsize, "Channel2 buffer size (default:1920 x 1080 x 2)");
-MODULE_PARM_DESC(ch3_bufsize, "Channel3 buffer size (default:720 x 576 x 2)");
-
-static struct vpif_config_params config_params = {
- .min_numbuffers = 3,
- .numbuffers[0] = 3,
- .numbuffers[1] = 3,
- .min_bufsize[0] = 720 * 480 * 2,
- .min_bufsize[1] = 720 * 480 * 2,
- .channel_bufsize[0] = 1920 * 1080 * 2,
- .channel_bufsize[1] = 720 * 576 * 2,
-};
+
+#define VPIF_DRIVER_NAME "vpif_display"
+
+/* Is set to 1 in case of SDTV formats, 2 in case of HDTV formats. */
+static int ycmux_mode;
+
+static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} };
static struct vpif_device vpif_obj = { {NULL} };
static struct device *vpif_dev;
static void vpif_calculate_offsets(struct channel_obj *ch);
static void vpif_config_addr(struct channel_obj *ch, int muxmode);
-/*
- * buffer_prepare: This is the callback function called from vb2_qbuf()
- * function the buffer is prepared and user space virtual address is converted
- * into physical address
+static inline struct vpif_disp_buffer *to_vpif_buffer(struct vb2_buffer *vb)
+{
+ return container_of(vb, struct vpif_disp_buffer, vb);
+}
+
+/**
+ * vpif_buffer_prepare : callback function for buffer prepare
+ * @vb: ptr to vb2_buffer
+ *
+ * This is the callback function for buffer prepare when vb2_qbuf()
+ * function is called. The buffer is prepared and user space virtual address
+ * or user address is converted into physical address
*/
static int vpif_buffer_prepare(struct vb2_buffer *vb)
{
- struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
- struct vb2_queue *q = vb->vb2_queue;
+ struct channel_obj *ch = vb2_get_drv_priv(vb->vb2_queue);
struct common_obj *common;
- unsigned long addr;
-
- common = &fh->channel->common[VPIF_VIDEO_INDEX];
- if (vb->state != VB2_BUF_STATE_ACTIVE &&
- vb->state != VB2_BUF_STATE_PREPARED) {
- vb2_set_plane_payload(vb, 0, common->fmt.fmt.pix.sizeimage);
- if (vb2_plane_vaddr(vb, 0) &&
- vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))
- goto buf_align_exit;
-
- addr = vb2_dma_contig_plane_dma_addr(vb, 0);
- if (q->streaming &&
- (V4L2_BUF_TYPE_SLICED_VBI_OUTPUT != q->type)) {
- if (!ISALIGNED(addr + common->ytop_off) ||
+
+ common = &ch->common[VPIF_VIDEO_INDEX];
+
+ vb2_set_plane_payload(vb, 0, common->fmt.fmt.pix.sizeimage);
+ if (vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))
+ return -EINVAL;
+
+ vb->v4l2_buf.field = common->fmt.fmt.pix.field;
+
+ if (vb->vb2_queue->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
+ unsigned long addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+
+ if (!ISALIGNED(addr + common->ytop_off) ||
!ISALIGNED(addr + common->ybtm_off) ||
!ISALIGNED(addr + common->ctop_off) ||
- !ISALIGNED(addr + common->cbtm_off))
- goto buf_align_exit;
+ !ISALIGNED(addr + common->cbtm_off)) {
+ vpif_err("buffer offset not aligned to 8 bytes\n");
+ return -EINVAL;
}
}
- return 0;
-buf_align_exit:
- vpif_err("buffer offset not aligned to 8 bytes\n");
- return -EINVAL;
+ return 0;
}
-/*
- * vpif_buffer_queue_setup: This function allocates memory for the buffers
+/**
+ * vpif_buffer_queue_setup : Callback function for buffer setup.
+ * @vq: vb2_queue ptr
+ * @fmt: v4l2 format
+ * @nbuffers: ptr to number of buffers requested by application
+ * @nplanes:: contains number of distinct video planes needed to hold a frame
+ * @sizes[]: contains the size (in bytes) of each plane.
+ * @alloc_ctxs: ptr to allocation context
+ *
+ * This callback function is called when reqbuf() is called to adjust
+ * the buffer count and buffer size
*/
static int vpif_buffer_queue_setup(struct vb2_queue *vq,
const struct v4l2_format *fmt,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
+ struct channel_obj *ch = vb2_get_drv_priv(vq);
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- unsigned long size;
-
- if (V4L2_MEMORY_MMAP == common->memory) {
- size = config_params.channel_bufsize[ch->channel_id];
- /*
- * Checking if the buffer size exceeds the available buffer
- * ycmux_mode = 0 means 1 channel mode HD and
- * ycmux_mode = 1 means 2 channels mode SD
- */
- if (ch->vpifparams.std_info.ycmux_mode == 0) {
- if (config_params.video_limit[ch->channel_id])
- while (size * *nbuffers >
- (config_params.video_limit[0]
- + config_params.video_limit[1]))
- (*nbuffers)--;
- } else {
- if (config_params.video_limit[ch->channel_id])
- while (size * *nbuffers >
- config_params.video_limit[ch->channel_id])
- (*nbuffers)--;
- }
- } else {
- size = common->fmt.fmt.pix.sizeimage;
- }
- if (*nbuffers < config_params.min_numbuffers)
- *nbuffers = config_params.min_numbuffers;
+ if (fmt && fmt->fmt.pix.sizeimage < common->fmt.fmt.pix.sizeimage)
+ return -EINVAL;
+
+ if (vq->num_buffers + *nbuffers < 3)
+ *nbuffers = 3 - vq->num_buffers;
*nplanes = 1;
- sizes[0] = size;
+ sizes[0] = fmt ? fmt->fmt.pix.sizeimage : common->fmt.fmt.pix.sizeimage;
alloc_ctxs[0] = common->alloc_ctx;
+
+ /* Calculate the offset for Y and C data in the buffer */
+ vpif_calculate_offsets(ch);
+
return 0;
}
-/*
- * vpif_buffer_queue: This function adds the buffer to DMA queue
+/**
+ * vpif_buffer_queue : Callback function to add buffer to DMA queue
+ * @vb: ptr to vb2_buffer
+ *
+ * This callback fucntion queues the buffer to DMA engine
*/
static void vpif_buffer_queue(struct vb2_buffer *vb)
{
- struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
- struct vpif_disp_buffer *buf = container_of(vb,
- struct vpif_disp_buffer, vb);
- struct channel_obj *ch = fh->channel;
+ struct vpif_disp_buffer *buf = to_vpif_buffer(vb);
+ struct channel_obj *ch = vb2_get_drv_priv(vb->vb2_queue);
struct common_obj *common;
unsigned long flags;
@@ -169,98 +151,26 @@ static void vpif_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&common->irqlock, flags);
}
-/*
- * vpif_buf_cleanup: This function is called from the videobuf2 layer to
- * free memory allocated to the buffers
+/**
+ * vpif_start_streaming : Starts the DMA engine for streaming
+ * @vb: ptr to vb2_buffer
+ * @count: number of buffers
*/
-static void vpif_buf_cleanup(struct vb2_buffer *vb)
-{
- struct vpif_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
- struct vpif_disp_buffer *buf = container_of(vb,
- struct vpif_disp_buffer, vb);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
- unsigned long flags;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
-
- spin_lock_irqsave(&common->irqlock, flags);
- if (vb->state == VB2_BUF_STATE_ACTIVE)
- list_del_init(&buf->list);
- spin_unlock_irqrestore(&common->irqlock, flags);
-}
-
-static void vpif_wait_prepare(struct vb2_queue *vq)
-{
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
- mutex_unlock(&common->lock);
-}
-
-static void vpif_wait_finish(struct vb2_queue *vq)
-{
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
-
- common = &ch->common[VPIF_VIDEO_INDEX];
- mutex_lock(&common->lock);
-}
-
-static int vpif_buffer_init(struct vb2_buffer *vb)
-{
- struct vpif_disp_buffer *buf = container_of(vb,
- struct vpif_disp_buffer, vb);
-
- INIT_LIST_HEAD(&buf->list);
-
- return 0;
-}
-
-static u8 channel_first_int[VPIF_NUMOBJECTS][2] = { {1, 1} };
-
static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct vpif_display_config *vpif_config_data =
vpif_dev->platform_data;
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
+ struct channel_obj *ch = vb2_get_drv_priv(vq);
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
struct vpif_params *vpif = &ch->vpifparams;
- unsigned long addr = 0;
- unsigned long flags;
+ struct vpif_disp_buffer *buf, *tmp;
+ unsigned long addr, flags;
int ret;
spin_lock_irqsave(&common->irqlock, flags);
- /* Get the next frame from the buffer queue */
- common->next_frm = common->cur_frm =
- list_entry(common->dma_queue.next,
- struct vpif_disp_buffer, list);
-
- list_del(&common->cur_frm->list);
- spin_unlock_irqrestore(&common->irqlock, flags);
- /* Mark state of the current frame to active */
- common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
-
- /* Initialize field_id and started member */
+ /* Initialize field_id */
ch->field_id = 0;
- common->started = 1;
- addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
- /* Calculate the offset for Y and C data in the buffer */
- vpif_calculate_offsets(ch);
-
- if ((ch->vpifparams.std_info.frm_fmt &&
- ((common->fmt.fmt.pix.field != V4L2_FIELD_NONE)
- && (common->fmt.fmt.pix.field != V4L2_FIELD_ANY)))
- || (!ch->vpifparams.std_info.frm_fmt
- && (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {
- vpif_err("conflict in field format and std format\n");
- return -EINVAL;
- }
/* clock settings */
if (vpif_config_data->set_clock) {
@@ -268,24 +178,37 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
ycmux_mode, ch->vpifparams.std_info.hd_sd);
if (ret < 0) {
vpif_err("can't set clock\n");
- return ret;
+ goto err;
}
}
/* set the parameters and addresses */
ret = vpif_set_video_params(vpif, ch->channel_id + 2);
if (ret < 0)
- return ret;
+ goto err;
- common->started = ret;
+ ycmux_mode = ret;
vpif_config_addr(ch, ret);
+ /* Get the next frame from the buffer queue */
+ common->next_frm = common->cur_frm =
+ list_entry(common->dma_queue.next,
+ struct vpif_disp_buffer, list);
+
+ list_del(&common->cur_frm->list);
+ spin_unlock_irqrestore(&common->irqlock, flags);
+ /* Mark state of the current frame to active */
+ common->cur_frm->vb.state = VB2_BUF_STATE_ACTIVE;
+
+ addr = vb2_dma_contig_plane_dma_addr(&common->cur_frm->vb, 0);
common->set_addr((addr + common->ytop_off),
(addr + common->ybtm_off),
(addr + common->ctop_off),
(addr + common->cbtm_off));
- /* Set interrupt for both the fields in VPIF
- Register enable channel in VPIF register */
+ /*
+ * Set interrupt for both the fields in VPIF
+ * Register enable channel in VPIF register
+ */
channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
channel2_intr_assert();
@@ -295,8 +218,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
channel2_clipping_enable(1);
}
- if ((VPIF_CHANNEL3_VIDEO == ch->channel_id)
- || (common->started == 2)) {
+ if (VPIF_CHANNEL3_VIDEO == ch->channel_id || ycmux_mode == 2) {
channel3_intr_assert();
channel3_intr_enable(1);
enable_channel3(1);
@@ -305,19 +227,29 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
}
return 0;
+
+err:
+ list_for_each_entry_safe(buf, tmp, &common->dma_queue, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+ }
+
+ return ret;
}
-/* abort streaming and wait for last buffer */
-static int vpif_stop_streaming(struct vb2_queue *vq)
+/**
+ * vpif_stop_streaming : Stop the DMA engine
+ * @vq: ptr to vb2_queue
+ *
+ * This callback stops the DMA engine and any remaining buffers
+ * in the DMA queue are released.
+ */
+static void vpif_stop_streaming(struct vb2_queue *vq)
{
- struct vpif_fh *fh = vb2_get_drv_priv(vq);
- struct channel_obj *ch = fh->channel;
+ struct channel_obj *ch = vb2_get_drv_priv(vq);
struct common_obj *common;
unsigned long flags;
- if (!vb2_is_streaming(vq))
- return 0;
-
common = &ch->common[VPIF_VIDEO_INDEX];
/* Disable channel */
@@ -325,12 +257,10 @@ static int vpif_stop_streaming(struct vb2_queue *vq)
enable_channel2(0);
channel2_intr_enable(0);
}
- if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) ||
- (2 == common->started)) {
+ if (VPIF_CHANNEL3_VIDEO == ch->channel_id || ycmux_mode == 2) {
enable_channel3(0);
channel3_intr_enable(0);
}
- common->started = 0;
/* release all active buffers */
spin_lock_irqsave(&common->irqlock, flags);
@@ -352,19 +282,15 @@ static int vpif_stop_streaming(struct vb2_queue *vq)
vb2_buffer_done(&common->next_frm->vb, VB2_BUF_STATE_ERROR);
}
spin_unlock_irqrestore(&common->irqlock, flags);
-
- return 0;
}
static struct vb2_ops video_qops = {
.queue_setup = vpif_buffer_queue_setup,
- .wait_prepare = vpif_wait_prepare,
- .wait_finish = vpif_wait_finish,
- .buf_init = vpif_buffer_init,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
.buf_prepare = vpif_buffer_prepare,
.start_streaming = vpif_start_streaming,
.stop_streaming = vpif_stop_streaming,
- .buf_cleanup = vpif_buf_cleanup,
.buf_queue = vpif_buffer_queue,
};
@@ -446,8 +372,6 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
for (i = 0; i < VPIF_NUMOBJECTS; i++) {
common = &ch->common[i];
/* If streaming is started in this channel */
- if (0 == common->started)
- continue;
if (1 == ch->vpifparams.std_info.frm_fmt) {
spin_lock(&common->irqlock);
@@ -543,6 +467,7 @@ static int vpif_update_resolution(struct channel_obj *ch)
return -EINVAL;
}
+ common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
common->fmt.fmt.pix.width = std_info->width;
common->fmt.fmt.pix.height = std_info->height;
vpif_dbg(1, debug, "Pixel details: Width = %d,Height = %d\n",
@@ -551,6 +476,17 @@ static int vpif_update_resolution(struct channel_obj *ch)
/* Set height and width paramateres */
common->height = std_info->height;
common->width = std_info->width;
+ common->fmt.fmt.pix.sizeimage = common->height * common->width * 2;
+
+ if (vid_ch->stdid)
+ common->fmt.fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
+ else
+ common->fmt.fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+
+ if (ch->vpifparams.std_info.frm_fmt)
+ common->fmt.fmt.pix.field = V4L2_FIELD_NONE;
+ else
+ common->fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
return 0;
}
@@ -621,70 +557,6 @@ static void vpif_calculate_offsets(struct channel_obj *ch)
ch->vpifparams.video_params.stdid = ch->vpifparams.std_info.stdid;
}
-static void vpif_config_format(struct channel_obj *ch)
-{
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- common->fmt.fmt.pix.field = V4L2_FIELD_ANY;
- if (config_params.numbuffers[ch->channel_id] == 0)
- common->memory = V4L2_MEMORY_USERPTR;
- else
- common->memory = V4L2_MEMORY_MMAP;
-
- common->fmt.fmt.pix.sizeimage =
- config_params.channel_bufsize[ch->channel_id];
- common->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV422P;
- common->fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
-}
-
-static int vpif_check_format(struct channel_obj *ch,
- struct v4l2_pix_format *pixfmt)
-{
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- enum v4l2_field field = pixfmt->field;
- u32 sizeimage, hpitch, vpitch;
-
- if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P)
- goto invalid_fmt_exit;
-
- if (!(VPIF_VALID_FIELD(field)))
- goto invalid_fmt_exit;
-
- if (pixfmt->bytesperline <= 0)
- goto invalid_pitch_exit;
-
- sizeimage = pixfmt->sizeimage;
-
- if (vpif_update_resolution(ch))
- return -EINVAL;
-
- hpitch = pixfmt->bytesperline;
- vpitch = sizeimage / (hpitch * 2);
-
- /* Check for valid value of pitch */
- if ((hpitch < ch->vpifparams.std_info.width) ||
- (vpitch < ch->vpifparams.std_info.height))
- goto invalid_pitch_exit;
-
- /* Check for 8 byte alignment */
- if (!ISALIGNED(hpitch)) {
- vpif_err("invalid pitch alignment\n");
- return -EINVAL;
- }
- pixfmt->width = common->fmt.fmt.pix.width;
- pixfmt->height = common->fmt.fmt.pix.height;
-
- return 0;
-
-invalid_fmt_exit:
- vpif_err("invalid field format\n");
- return -EINVAL;
-
-invalid_pitch_exit:
- vpif_err("invalid pitch\n");
- return -EINVAL;
-}
-
static void vpif_config_addr(struct channel_obj *ch, int muxmode)
{
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
@@ -699,127 +571,6 @@ static void vpif_config_addr(struct channel_obj *ch, int muxmode)
}
}
-/*
- * vpif_mmap: It is used to map kernel space buffers into user spaces
- */
-static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
-{
- struct vpif_fh *fh = filep->private_data;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
- int ret;
-
- vpif_dbg(2, debug, "vpif_mmap\n");
-
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
- ret = vb2_mmap(&common->buffer_queue, vma);
- mutex_unlock(&common->lock);
- return ret;
-}
-
-/*
- * vpif_poll: It is used for select/poll system call
- */
-static unsigned int vpif_poll(struct file *filep, poll_table *wait)
-{
- struct vpif_fh *fh = filep->private_data;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- unsigned int res = 0;
-
- if (common->started) {
- mutex_lock(&common->lock);
- res = vb2_poll(&common->buffer_queue, filep, wait);
- mutex_unlock(&common->lock);
- }
-
- return res;
-}
-
-/*
- * vpif_open: It creates object of file handle structure and stores it in
- * private_data member of filepointer
- */
-static int vpif_open(struct file *filep)
-{
- struct video_device *vdev = video_devdata(filep);
- struct channel_obj *ch = video_get_drvdata(vdev);
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct vpif_fh *fh;
-
- /* Allocate memory for the file handle object */
- fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);
- if (fh == NULL) {
- vpif_err("unable to allocate memory for file handle object\n");
- return -ENOMEM;
- }
-
- if (mutex_lock_interruptible(&common->lock)) {
- kfree(fh);
- return -ERESTARTSYS;
- }
- /* store pointer to fh in private_data member of filep */
- filep->private_data = fh;
- fh->channel = ch;
- fh->initialized = 0;
- if (!ch->initialized) {
- fh->initialized = 1;
- ch->initialized = 1;
- memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));
- }
-
- /* Increment channel usrs counter */
- atomic_inc(&ch->usrs);
- /* Set io_allowed[VPIF_VIDEO_INDEX] member to false */
- fh->io_allowed[VPIF_VIDEO_INDEX] = 0;
- /* Initialize priority of this instance to default priority */
- fh->prio = V4L2_PRIORITY_UNSET;
- v4l2_prio_open(&ch->prio, &fh->prio);
- mutex_unlock(&common->lock);
-
- return 0;
-}
-
-/*
- * vpif_release: This function deletes buffer queue, frees the buffers and
- * the vpif file handle
- */
-static int vpif_release(struct file *filep)
-{
- struct vpif_fh *fh = filep->private_data;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- mutex_lock(&common->lock);
- /* if this instance is doing IO */
- if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
- /* Reset io_usrs member of channel object */
- common->io_usrs = 0;
- /* Free buffers allocated */
- vb2_queue_release(&common->buffer_queue);
- vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
-
- common->numbuffers =
- config_params.numbuffers[ch->channel_id];
- }
-
- /* Decrement channel usrs counter */
- atomic_dec(&ch->usrs);
- /* If this file handle has initialize encoder device, reset it */
- if (fh->initialized)
- ch->initialized = 0;
-
- /* Close the priority */
- v4l2_prio_close(&ch->prio, fh->prio);
- filep->private_data = NULL;
- fh->initialized = 0;
- mutex_unlock(&common->lock);
- kfree(fh);
-
- return 0;
-}
-
/* functions implementing ioctls */
/**
* vpif_querycap() - QUERYCAP handler
@@ -834,7 +585,7 @@ static int vpif_querycap(struct file *file, void *priv,
cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
- snprintf(cap->driver, sizeof(cap->driver), "%s", dev_name(vpif_dev));
+ strlcpy(cap->driver, VPIF_DRIVER_NAME, sizeof(cap->driver));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(vpif_dev));
strlcpy(cap->card, config->card_name, sizeof(cap->card));
@@ -845,24 +596,22 @@ static int vpif_querycap(struct file *file, void *priv,
static int vpif_enum_fmt_vid_out(struct file *file, void *priv,
struct v4l2_fmtdesc *fmt)
{
- if (fmt->index != 0) {
- vpif_err("Invalid format index\n");
+ if (fmt->index != 0)
return -EINVAL;
- }
/* Fill in the information about format */
fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
strcpy(fmt->description, "YCbCr4:2:2 YC Planar");
fmt->pixelformat = V4L2_PIX_FMT_YUV422P;
-
+ fmt->flags = 0;
return 0;
}
static int vpif_g_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
/* Check the validity of the buffer type */
@@ -875,193 +624,84 @@ static int vpif_g_fmt_vid_out(struct file *file, void *priv,
return 0;
}
-static int vpif_s_fmt_vid_out(struct file *file, void *priv,
+static int vpif_try_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct vpif_fh *fh = priv;
- struct v4l2_pix_format *pixfmt;
- struct channel_obj *ch = fh->channel;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- int ret = 0;
-
- if ((VPIF_CHANNEL2_VIDEO == ch->channel_id)
- || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) {
- if (!fh->initialized) {
- vpif_dbg(1, debug, "Channel Busy\n");
- return -EBUSY;
- }
+ struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
- /* Check for the priority */
- ret = v4l2_prio_check(&ch->prio, fh->prio);
- if (0 != ret)
- return ret;
- fh->initialized = 1;
- }
+ /*
+ * to supress v4l-compliance warnings silently correct
+ * the pixelformat
+ */
+ if (pixfmt->pixelformat != V4L2_PIX_FMT_YUV422P)
+ pixfmt->pixelformat = common->fmt.fmt.pix.pixelformat;
- if (common->started) {
- vpif_dbg(1, debug, "Streaming in progress\n");
- return -EBUSY;
- }
+ if (vpif_update_resolution(ch))
+ return -EINVAL;
- pixfmt = &fmt->fmt.pix;
- /* Check for valid field format */
- ret = vpif_check_format(ch, pixfmt);
- if (ret)
- return ret;
+ pixfmt->colorspace = common->fmt.fmt.pix.colorspace;
+ pixfmt->field = common->fmt.fmt.pix.field;
+ pixfmt->bytesperline = common->fmt.fmt.pix.width;
+ pixfmt->width = common->fmt.fmt.pix.width;
+ pixfmt->height = common->fmt.fmt.pix.height;
+ pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height * 2;
+ pixfmt->priv = 0;
- /* store the pix format in the channel object */
- common->fmt.fmt.pix = *pixfmt;
- /* store the format in the channel object */
- common->fmt = *fmt;
return 0;
}
-static int vpif_try_fmt_vid_out(struct file *file, void *priv,
+static int vpif_s_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
- int ret = 0;
-
- ret = vpif_check_format(ch, pixfmt);
- if (ret) {
- *pixfmt = common->fmt.fmt.pix;
- pixfmt->sizeimage = pixfmt->width * pixfmt->height * 2;
- }
-
- return ret;
-}
-
-static int vpif_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *reqbuf)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common;
- enum v4l2_field field;
- struct vb2_queue *q;
- u8 index = 0;
int ret;
- /* This file handle has not initialized the channel,
- It is not allowed to do settings */
- if ((VPIF_CHANNEL2_VIDEO == ch->channel_id)
- || (VPIF_CHANNEL3_VIDEO == ch->channel_id)) {
- if (!fh->initialized) {
- vpif_err("Channel Busy\n");
- return -EBUSY;
- }
- }
-
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != reqbuf->type)
- return -EINVAL;
-
- index = VPIF_VIDEO_INDEX;
-
- common = &ch->common[index];
-
- if (common->fmt.type != reqbuf->type || !vpif_dev)
- return -EINVAL;
- if (0 != common->io_usrs)
+ if (vb2_is_busy(&common->buffer_queue))
return -EBUSY;
- if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY)
- field = V4L2_FIELD_INTERLACED;
- else
- field = common->fmt.fmt.pix.field;
- } else {
- field = V4L2_VBI_INTERLACED;
- }
- /* Initialize videobuf2 queue as per the buffer type */
- common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev);
- if (IS_ERR(common->alloc_ctx)) {
- vpif_err("Failed to get the context\n");
- return PTR_ERR(common->alloc_ctx);
- }
- q = &common->buffer_queue;
- q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- q->io_modes = VB2_MMAP | VB2_USERPTR;
- q->drv_priv = fh;
- q->ops = &video_qops;
- q->mem_ops = &vb2_dma_contig_memops;
- q->buf_struct_size = sizeof(struct vpif_disp_buffer);
- q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 1;
-
- ret = vb2_queue_init(q);
- if (ret) {
- vpif_err("vpif_display: vb2_queue_init() failed\n");
- vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
+ ret = vpif_try_fmt_vid_out(file, priv, fmt);
+ if (ret)
return ret;
- }
- /* Set io allowed member of file handle to TRUE */
- fh->io_allowed[index] = 1;
- /* Increment io usrs member of channel object to 1 */
- common->io_usrs = 1;
- /* Store type of memory requested in channel object */
- common->memory = reqbuf->memory;
- INIT_LIST_HEAD(&common->dma_queue);
- /* Allocate buffers */
- return vb2_reqbufs(&common->buffer_queue, reqbuf);
-}
-
-static int vpif_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *tbuf)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- if (common->fmt.type != tbuf->type)
- return -EINVAL;
+ /* store the pix format in the channel object */
+ common->fmt.fmt.pix = *pixfmt;
- return vb2_querybuf(&common->buffer_queue, tbuf);
+ /* store the format in the channel object */
+ common->fmt = *fmt;
+ return 0;
}
-static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id)
{
- struct vpif_fh *fh = NULL;
- struct channel_obj *ch = NULL;
- struct common_obj *common = NULL;
-
- if (!buf || !priv)
- return -EINVAL;
-
- fh = priv;
- ch = fh->channel;
- if (!ch)
- return -EINVAL;
+ struct vpif_display_config *config = vpif_dev->platform_data;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct vpif_display_chan_config *chan_cfg;
+ struct v4l2_output output;
+ int ret;
- common = &(ch->common[VPIF_VIDEO_INDEX]);
- if (common->fmt.type != buf->type)
- return -EINVAL;
+ if (config->chan_config[ch->channel_id].outputs == NULL)
+ return -ENODATA;
- if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
- vpif_err("fh->io_allowed\n");
- return -EACCES;
- }
+ chan_cfg = &config->chan_config[ch->channel_id];
+ output = chan_cfg->outputs[ch->output_idx].output;
+ if (output.capabilities != V4L2_OUT_CAP_STD)
+ return -ENODATA;
- return vb2_qbuf(&common->buffer_queue, buf);
-}
+ if (vb2_is_busy(&common->buffer_queue))
+ return -EBUSY;
-static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- int ret = 0;
if (!(std_id & VPIF_V4L2_STD))
return -EINVAL;
- if (common->started) {
- vpif_err("streaming in progress\n");
- return -EBUSY;
- }
-
/* Call encoder subdevice function to set the standard */
ch->video.stdid = std_id;
memset(&ch->video.dv_timings, 0, sizeof(ch->video.dv_timings));
@@ -1069,16 +709,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id)
if (vpif_update_resolution(ch))
return -EINVAL;
- if ((ch->vpifparams.std_info.width *
- ch->vpifparams.std_info.height * 2) >
- config_params.channel_bufsize[ch->channel_id]) {
- vpif_err("invalid std for this size\n");
- return -EINVAL;
- }
-
common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width;
- /* Configure the default format information */
- vpif_config_format(ch);
ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,
s_std_output, std_id);
@@ -1087,7 +718,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id)
return ret;
}
- ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core,
+ ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,
s_std, std_id);
if (ret < 0)
vpif_err("Failed to set standard for sub devices\n");
@@ -1096,132 +727,21 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id)
static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- *std = ch->video.stdid;
- return 0;
-}
-
-static int vpif_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
-
- return vb2_dqbuf(&common->buffer_queue, p,
- (file->f_flags & O_NONBLOCK));
-}
-
-static int vpif_streamon(struct file *file, void *priv,
- enum v4l2_buf_type buftype)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct channel_obj *oth_ch = vpif_obj.dev[!ch->channel_id];
- int ret = 0;
-
- if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- vpif_err("buffer type not supported\n");
- return -EINVAL;
- }
-
- if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
- vpif_err("fh->io_allowed\n");
- return -EACCES;
- }
-
- /* If Streaming is already started, return error */
- if (common->started) {
- vpif_err("channel->started\n");
- return -EBUSY;
- }
-
- if ((ch->channel_id == VPIF_CHANNEL2_VIDEO
- && oth_ch->common[VPIF_VIDEO_INDEX].started &&
- ch->vpifparams.std_info.ycmux_mode == 0)
- || ((ch->channel_id == VPIF_CHANNEL3_VIDEO)
- && (2 == oth_ch->common[VPIF_VIDEO_INDEX].started))) {
- vpif_err("other channel is using\n");
- return -EBUSY;
- }
-
- ret = vpif_check_format(ch, &common->fmt.fmt.pix);
- if (ret < 0)
- return ret;
-
- /* Call vb2_streamon to start streaming in videobuf2 */
- ret = vb2_streamon(&common->buffer_queue, buftype);
- if (ret < 0) {
- vpif_err("vb2_streamon\n");
- return ret;
- }
-
- return ret;
-}
-
-static int vpif_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type buftype)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- struct vpif_display_config *vpif_config_data =
- vpif_dev->platform_data;
-
- if (buftype != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- vpif_err("buffer type not supported\n");
- return -EINVAL;
- }
-
- if (!fh->io_allowed[VPIF_VIDEO_INDEX]) {
- vpif_err("fh->io_allowed\n");
- return -EACCES;
- }
-
- if (!common->started) {
- vpif_err("channel->started\n");
- return -EINVAL;
- }
-
- if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- /* disable channel */
- if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
- if (vpif_config_data->
- chan_config[VPIF_CHANNEL2_VIDEO].clip_en)
- channel2_clipping_enable(0);
- enable_channel2(0);
- channel2_intr_enable(0);
- }
- if ((VPIF_CHANNEL3_VIDEO == ch->channel_id) ||
- (2 == common->started)) {
- if (vpif_config_data->
- chan_config[VPIF_CHANNEL3_VIDEO].clip_en)
- channel3_clipping_enable(0);
- enable_channel3(0);
- channel3_intr_enable(0);
- }
- }
-
- common->started = 0;
- return vb2_streamoff(&common->buffer_queue, buftype);
-}
+ struct vpif_display_config *config = vpif_dev->platform_data;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
+ struct vpif_display_chan_config *chan_cfg;
+ struct v4l2_output output;
-static int vpif_cropcap(struct file *file, void *priv,
- struct v4l2_cropcap *crop)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != crop->type)
- return -EINVAL;
+ if (config->chan_config[ch->channel_id].outputs == NULL)
+ return -ENODATA;
- crop->bounds.left = crop->bounds.top = 0;
- crop->defrect.left = crop->defrect.top = 0;
- crop->defrect.height = crop->bounds.height = common->height;
- crop->defrect.width = crop->bounds.width = common->width;
+ chan_cfg = &config->chan_config[ch->channel_id];
+ output = chan_cfg->outputs[ch->output_idx].output;
+ if (output.capabilities != V4L2_OUT_CAP_STD)
+ return -ENODATA;
+ *std = ch->video.stdid;
return 0;
}
@@ -1230,9 +750,9 @@ static int vpif_enum_output(struct file *file, void *fh,
{
struct vpif_display_config *config = vpif_dev->platform_data;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
struct vpif_display_chan_config *chan_cfg;
- struct vpif_fh *vpif_handler = fh;
- struct channel_obj *ch = vpif_handler->channel;
chan_cfg = &config->chan_config[ch->channel_id];
if (output->index >= chan_cfg->output_count) {
@@ -1326,52 +846,32 @@ static int vpif_set_output(struct vpif_display_config *vpif_cfg,
static int vpif_s_output(struct file *file, void *priv, unsigned int i)
{
struct vpif_display_config *config = vpif_dev->platform_data;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
struct vpif_display_chan_config *chan_cfg;
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ if (vb2_is_busy(&common->buffer_queue))
+ return -EBUSY;
+
chan_cfg = &config->chan_config[ch->channel_id];
if (i >= chan_cfg->output_count)
return -EINVAL;
- if (common->started) {
- vpif_err("Streaming in progress\n");
- return -EBUSY;
- }
-
return vpif_set_output(config, ch, i);
}
static int vpif_g_output(struct file *file, void *priv, unsigned int *i)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
*i = ch->output_idx;
return 0;
}
-static int vpif_g_priority(struct file *file, void *priv, enum v4l2_priority *p)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- *p = v4l2_prio_max(&ch->prio);
-
- return 0;
-}
-
-static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p)
-{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
-
- return v4l2_prio_change(&ch->prio, &fh->prio, p);
-}
-
/**
* vpif_enum_dv_timings() - ENUM_DV_TIMINGS handler
* @file: file ptr
@@ -1382,11 +882,24 @@ static int
vpif_enum_dv_timings(struct file *file, void *priv,
struct v4l2_enum_dv_timings *timings)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct vpif_display_config *config = vpif_dev->platform_data;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
+ struct vpif_display_chan_config *chan_cfg;
+ struct v4l2_output output;
int ret;
- ret = v4l2_subdev_call(ch->sd, video, enum_dv_timings, timings);
+ if (config->chan_config[ch->channel_id].outputs == NULL)
+ return -ENODATA;
+
+ chan_cfg = &config->chan_config[ch->channel_id];
+ output = chan_cfg->outputs[ch->output_idx].output;
+ if (output.capabilities != V4L2_OUT_CAP_DV_TIMINGS)
+ return -ENODATA;
+
+ timings->pad = 0;
+
+ ret = v4l2_subdev_call(ch->sd, pad, enum_dv_timings, timings);
if (ret == -ENOIOCTLCMD || ret == -ENODEV)
return -EINVAL;
return ret;
@@ -1401,14 +914,29 @@ vpif_enum_dv_timings(struct file *file, void *priv,
static int vpif_s_dv_timings(struct file *file, void *priv,
struct v4l2_dv_timings *timings)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct vpif_display_config *config = vpif_dev->platform_data;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
struct vpif_params *vpifparams = &ch->vpifparams;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
struct vpif_channel_config_params *std_info = &vpifparams->std_info;
struct video_obj *vid_ch = &ch->video;
struct v4l2_bt_timings *bt = &vid_ch->dv_timings.bt;
+ struct vpif_display_chan_config *chan_cfg;
+ struct v4l2_output output;
int ret;
+ if (config->chan_config[ch->channel_id].outputs == NULL)
+ return -ENODATA;
+
+ chan_cfg = &config->chan_config[ch->channel_id];
+ output = chan_cfg->outputs[ch->output_idx].output;
+ if (output.capabilities != V4L2_OUT_CAP_DV_TIMINGS)
+ return -ENODATA;
+
+ if (vb2_is_busy(&common->buffer_queue))
+ return -EBUSY;
+
if (timings->type != V4L2_DV_BT_656_1120) {
vpif_dbg(2, debug, "Timing type not defined\n");
return -EINVAL;
@@ -1490,13 +1018,27 @@ static int vpif_s_dv_timings(struct file *file, void *priv,
static int vpif_g_dv_timings(struct file *file, void *priv,
struct v4l2_dv_timings *timings)
{
- struct vpif_fh *fh = priv;
- struct channel_obj *ch = fh->channel;
+ struct vpif_display_config *config = vpif_dev->platform_data;
+ struct video_device *vdev = video_devdata(file);
+ struct channel_obj *ch = video_get_drvdata(vdev);
+ struct vpif_display_chan_config *chan_cfg;
struct video_obj *vid_ch = &ch->video;
+ struct v4l2_output output;
+
+ if (config->chan_config[ch->channel_id].outputs == NULL)
+ goto error;
+
+ chan_cfg = &config->chan_config[ch->channel_id];
+ output = chan_cfg->outputs[ch->output_idx].output;
+
+ if (output.capabilities != V4L2_OUT_CAP_DV_TIMINGS)
+ goto error;
*timings = vid_ch->dv_timings;
return 0;
+error:
+ return -ENODATA;
}
/*
@@ -1516,83 +1058,49 @@ static int vpif_log_status(struct file *filep, void *priv)
/* vpif display ioctl operations */
static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
- .vidioc_querycap = vpif_querycap,
- .vidioc_g_priority = vpif_g_priority,
- .vidioc_s_priority = vpif_s_priority,
+ .vidioc_querycap = vpif_querycap,
.vidioc_enum_fmt_vid_out = vpif_enum_fmt_vid_out,
- .vidioc_g_fmt_vid_out = vpif_g_fmt_vid_out,
- .vidioc_s_fmt_vid_out = vpif_s_fmt_vid_out,
- .vidioc_try_fmt_vid_out = vpif_try_fmt_vid_out,
- .vidioc_reqbufs = vpif_reqbufs,
- .vidioc_querybuf = vpif_querybuf,
- .vidioc_qbuf = vpif_qbuf,
- .vidioc_dqbuf = vpif_dqbuf,
- .vidioc_streamon = vpif_streamon,
- .vidioc_streamoff = vpif_streamoff,
- .vidioc_s_std = vpif_s_std,
+ .vidioc_g_fmt_vid_out = vpif_g_fmt_vid_out,
+ .vidioc_s_fmt_vid_out = vpif_s_fmt_vid_out,
+ .vidioc_try_fmt_vid_out = vpif_try_fmt_vid_out,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+
+ .vidioc_s_std = vpif_s_std,
.vidioc_g_std = vpif_g_std,
+
.vidioc_enum_output = vpif_enum_output,
.vidioc_s_output = vpif_s_output,
.vidioc_g_output = vpif_g_output,
- .vidioc_cropcap = vpif_cropcap,
- .vidioc_enum_dv_timings = vpif_enum_dv_timings,
- .vidioc_s_dv_timings = vpif_s_dv_timings,
- .vidioc_g_dv_timings = vpif_g_dv_timings,
+
+ .vidioc_enum_dv_timings = vpif_enum_dv_timings,
+ .vidioc_s_dv_timings = vpif_s_dv_timings,
+ .vidioc_g_dv_timings = vpif_g_dv_timings,
+
.vidioc_log_status = vpif_log_status,
};
static const struct v4l2_file_operations vpif_fops = {
.owner = THIS_MODULE,
- .open = vpif_open,
- .release = vpif_release,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
.unlocked_ioctl = video_ioctl2,
- .mmap = vpif_mmap,
- .poll = vpif_poll
-};
-
-static struct video_device vpif_video_template = {
- .name = "vpif",
- .fops = &vpif_fops,
- .ioctl_ops = &vpif_ioctl_ops,
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll
};
/*Configure the channels, buffer sizei, request irq */
static int initialize_vpif(void)
{
int free_channel_objects_index;
- int free_buffer_channel_index;
- int free_buffer_index;
- int err = 0, i, j;
-
- /* Default number of buffers should be 3 */
- if ((ch2_numbuffers > 0) &&
- (ch2_numbuffers < config_params.min_numbuffers))
- ch2_numbuffers = config_params.min_numbuffers;
- if ((ch3_numbuffers > 0) &&
- (ch3_numbuffers < config_params.min_numbuffers))
- ch3_numbuffers = config_params.min_numbuffers;
-
- /* Set buffer size to min buffers size if invalid buffer size is
- * given */
- if (ch2_bufsize < config_params.min_bufsize[VPIF_CHANNEL2_VIDEO])
- ch2_bufsize =
- config_params.min_bufsize[VPIF_CHANNEL2_VIDEO];
- if (ch3_bufsize < config_params.min_bufsize[VPIF_CHANNEL3_VIDEO])
- ch3_bufsize =
- config_params.min_bufsize[VPIF_CHANNEL3_VIDEO];
-
- config_params.numbuffers[VPIF_CHANNEL2_VIDEO] = ch2_numbuffers;
-
- if (ch2_numbuffers) {
- config_params.channel_bufsize[VPIF_CHANNEL2_VIDEO] =
- ch2_bufsize;
- }
- config_params.numbuffers[VPIF_CHANNEL3_VIDEO] = ch3_numbuffers;
-
- if (ch3_numbuffers) {
- config_params.channel_bufsize[VPIF_CHANNEL3_VIDEO] =
- ch3_bufsize;
- }
+ int err, i, j;
/* Allocate memory for six channel objects */
for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
@@ -1606,10 +1114,6 @@ static int initialize_vpif(void)
}
}
- free_channel_objects_index = VPIF_DISPLAY_MAX_DEVICES;
- free_buffer_channel_index = VPIF_DISPLAY_NUM_CHANNELS;
- free_buffer_index = config_params.numbuffers[i - 1];
-
return 0;
vpif_init_free_channel_objects:
@@ -1638,21 +1142,18 @@ static int vpif_async_bound(struct v4l2_async_notifier *notifier,
static int vpif_probe_complete(void)
{
struct common_obj *common;
+ struct video_device *vdev;
struct channel_obj *ch;
+ struct vb2_queue *q;
int j, err, k;
for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
ch = vpif_obj.dev[j];
/* Initialize field of the channel objects */
- atomic_set(&ch->usrs, 0);
for (k = 0; k < VPIF_NUMOBJECTS; k++) {
- ch->common[k].numbuffers = 0;
common = &ch->common[k];
- common->io_usrs = 0;
- common->started = 0;
spin_lock_init(&common->irqlock);
mutex_init(&common->lock);
- common->numbuffers = 0;
common->set_addr = NULL;
common->ytop_off = 0;
common->ybtm_off = 0;
@@ -1661,38 +1162,71 @@ static int vpif_probe_complete(void)
common->cur_frm = NULL;
common->next_frm = NULL;
memset(&common->fmt, 0, sizeof(common->fmt));
- common->numbuffers = config_params.numbuffers[k];
}
ch->initialized = 0;
if (vpif_obj.config->subdev_count)
ch->sd = vpif_obj.sd[0];
ch->channel_id = j;
- if (j < 2)
- ch->common[VPIF_VIDEO_INDEX].numbuffers =
- config_params.numbuffers[ch->channel_id];
- else
- ch->common[VPIF_VIDEO_INDEX].numbuffers = 0;
memset(&ch->vpifparams, 0, sizeof(ch->vpifparams));
- /* Initialize prio member of channel object */
- v4l2_prio_init(&ch->prio);
ch->common[VPIF_VIDEO_INDEX].fmt.type =
V4L2_BUF_TYPE_VIDEO_OUTPUT;
- ch->video_dev->lock = &common->lock;
- video_set_drvdata(ch->video_dev, ch);
/* select output 0 */
err = vpif_set_output(vpif_obj.config, ch, 0);
if (err)
goto probe_out;
+ /* set initial format */
+ ch->video.stdid = V4L2_STD_525_60;
+ memset(&ch->video.dv_timings, 0, sizeof(ch->video.dv_timings));
+ vpif_update_resolution(ch);
+
+ /* Initialize vb2 queue */
+ q = &common->buffer_queue;
+ q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ q->drv_priv = ch;
+ q->ops = &video_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->buf_struct_size = sizeof(struct vpif_disp_buffer);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_buffers_needed = 1;
+ q->lock = &common->lock;
+ err = vb2_queue_init(q);
+ if (err) {
+ vpif_err("vpif_display: vb2_queue_init() failed\n");
+ goto probe_out;
+ }
+
+ common->alloc_ctx = vb2_dma_contig_init_ctx(vpif_dev);
+ if (IS_ERR(common->alloc_ctx)) {
+ vpif_err("Failed to get the context\n");
+ err = PTR_ERR(common->alloc_ctx);
+ goto probe_out;
+ }
+
+ INIT_LIST_HEAD(&common->dma_queue);
+
/* register video device */
vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",
(int)ch, (int)&ch->video_dev);
- err = video_register_device(ch->video_dev,
- VFL_TYPE_GRABBER, (j ? 3 : 2));
+ /* Initialize the video_device structure */
+ vdev = ch->video_dev;
+ strlcpy(vdev->name, VPIF_DRIVER_NAME, sizeof(vdev->name));
+ vdev->release = video_device_release;
+ vdev->fops = &vpif_fops;
+ vdev->ioctl_ops = &vpif_ioctl_ops;
+ vdev->v4l2_dev = &vpif_obj.v4l2_dev;
+ vdev->vfl_dir = VFL_DIR_TX;
+ vdev->queue = q;
+ vdev->lock = &common->lock;
+ set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags);
+ video_set_drvdata(ch->video_dev, ch);
+ err = video_register_device(vdev, VFL_TYPE_GRABBER,
+ (j ? 3 : 2));
if (err < 0)
goto probe_out;
}
@@ -1702,6 +1236,8 @@ static int vpif_probe_complete(void)
probe_out:
for (k = 0; k < j; k++) {
ch = vpif_obj.dev[k];
+ common = &ch->common[k];
+ vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
video_unregister_device(ch->video_dev);
video_device_release(ch->video_dev);
ch->video_dev = NULL;
@@ -1728,7 +1264,6 @@ static __init int vpif_probe(struct platform_device *pdev)
struct video_device *vfd;
struct resource *res;
int subdev_count;
- size_t size;
vpif_dev = &pdev->dev;
err = initialize_vpif();
@@ -1746,7 +1281,7 @@ static __init int vpif_probe(struct platform_device *pdev)
while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, res_idx))) {
err = devm_request_irq(&pdev->dev, res->start, vpif_channel_isr,
- IRQF_SHARED, "VPIF_Display",
+ IRQF_SHARED, VPIF_DRIVER_NAME,
(void *)(&vpif_obj.dev[res_idx]->
channel_id));
if (err) {
@@ -1772,36 +1307,10 @@ static __init int vpif_probe(struct platform_device *pdev)
goto vpif_unregister;
}
- /* Initialize field of video device */
- *vfd = vpif_video_template;
- vfd->v4l2_dev = &vpif_obj.v4l2_dev;
- vfd->release = video_device_release;
- vfd->vfl_dir = VFL_DIR_TX;
- snprintf(vfd->name, sizeof(vfd->name),
- "VPIF_Display_DRIVER_V%s",
- VPIF_DISPLAY_VERSION);
-
/* Set video_dev to the video device */
ch->video_dev = vfd;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (res) {
- size = resource_size(res);
- /* The resources are divided into two equal memory and when
- * we have HD output we can add them together
- */
- for (j = 0; j < VPIF_DISPLAY_MAX_DEVICES; j++) {
- ch = vpif_obj.dev[j];
- ch->channel_id = j;
-
- /* only enabled if second resource exists */
- config_params.video_limit[ch->channel_id] = 0;
- if (size)
- config_params.video_limit[ch->channel_id] =
- size/2;
- }
- }
vpif_obj.config = pdev->dev.platform_data;
subdev_count = vpif_obj.config->subdev_count;
subdevdata = vpif_obj.config->subdevinfo;
@@ -1867,6 +1376,7 @@ vpif_unregister:
*/
static int vpif_remove(struct platform_device *device)
{
+ struct common_obj *common;
struct channel_obj *ch;
int i;
@@ -1877,6 +1387,8 @@ static int vpif_remove(struct platform_device *device)
for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
/* Get the pointer to the channel object */
ch = vpif_obj.dev[i];
+ common = &ch->common[i];
+ vb2_dma_contig_cleanup_ctx(common->alloc_ctx);
/* Unregister video device */
video_unregister_device(ch->video_dev);
@@ -1887,7 +1399,7 @@ static int vpif_remove(struct platform_device *device)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int vpif_suspend(struct device *dev)
{
struct common_obj *common;
@@ -1898,18 +1410,20 @@ static int vpif_suspend(struct device *dev)
/* Get the pointer to the channel object */
ch = vpif_obj.dev[i];
common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (!vb2_is_streaming(&common->buffer_queue))
+ continue;
+
mutex_lock(&common->lock);
- if (atomic_read(&ch->usrs) && common->io_usrs) {
- /* Disable channel */
- if (ch->channel_id == VPIF_CHANNEL2_VIDEO) {
- enable_channel2(0);
- channel2_intr_enable(0);
- }
- if (ch->channel_id == VPIF_CHANNEL3_VIDEO ||
- common->started == 2) {
- enable_channel3(0);
- channel3_intr_enable(0);
- }
+ /* Disable channel */
+ if (ch->channel_id == VPIF_CHANNEL2_VIDEO) {
+ enable_channel2(0);
+ channel2_intr_enable(0);
+ }
+ if (ch->channel_id == VPIF_CHANNEL3_VIDEO ||
+ ycmux_mode == 2) {
+ enable_channel3(0);
+ channel3_intr_enable(0);
}
mutex_unlock(&common->lock);
}
@@ -1928,18 +1442,20 @@ static int vpif_resume(struct device *dev)
/* Get the pointer to the channel object */
ch = vpif_obj.dev[i];
common = &ch->common[VPIF_VIDEO_INDEX];
+
+ if (!vb2_is_streaming(&common->buffer_queue))
+ continue;
+
mutex_lock(&common->lock);
- if (atomic_read(&ch->usrs) && common->io_usrs) {
- /* Enable channel */
- if (ch->channel_id == VPIF_CHANNEL2_VIDEO) {
- enable_channel2(1);
- channel2_intr_enable(1);
- }
- if (ch->channel_id == VPIF_CHANNEL3_VIDEO ||
- common->started == 2) {
- enable_channel3(1);
- channel3_intr_enable(1);
- }
+ /* Enable channel */
+ if (ch->channel_id == VPIF_CHANNEL2_VIDEO) {
+ enable_channel2(1);
+ channel2_intr_enable(1);
+ }
+ if (ch->channel_id == VPIF_CHANNEL3_VIDEO ||
+ ycmux_mode == 2) {
+ enable_channel3(1);
+ channel3_intr_enable(1);
}
mutex_unlock(&common->lock);
}
@@ -1947,21 +1463,15 @@ static int vpif_resume(struct device *dev)
return 0;
}
-static const struct dev_pm_ops vpif_pm = {
- .suspend = vpif_suspend,
- .resume = vpif_resume,
-};
-
-#define vpif_pm_ops (&vpif_pm)
-#else
-#define vpif_pm_ops NULL
#endif
+static SIMPLE_DEV_PM_OPS(vpif_pm_ops, vpif_suspend, vpif_resume);
+
static __refdata struct platform_driver vpif_driver = {
.driver = {
- .name = "vpif_display",
+ .name = VPIF_DRIVER_NAME,
.owner = THIS_MODULE,
- .pm = vpif_pm_ops,
+ .pm = &vpif_pm_ops,
},
.probe = vpif_probe,
.remove = vpif_remove,
diff --git a/drivers/media/platform/davinci/vpif_display.h b/drivers/media/platform/davinci/vpif_display.h
index 4d0485b99a80..7b21a7607674 100644
--- a/drivers/media/platform/davinci/vpif_display.h
+++ b/drivers/media/platform/davinci/vpif_display.h
@@ -13,8 +13,8 @@
* GNU General Public License for more details.
*/
-#ifndef DAVINCIHD_DISPLAY_H
-#define DAVINCIHD_DISPLAY_H
+#ifndef VPIF_DISPLAY_H
+#define VPIF_DISPLAY_H
/* Header files */
#include <media/videobuf2-dma-contig.h>
@@ -67,17 +67,10 @@ struct vpif_disp_buffer {
};
struct common_obj {
- /* Buffer specific parameters */
- u8 *fbuffers[VIDEO_MAX_FRAME]; /* List of buffer pointers for
- * storing frames */
- u32 numbuffers; /* number of buffers */
struct vpif_disp_buffer *cur_frm; /* Pointer pointing to current
* vb2_buffer */
struct vpif_disp_buffer *next_frm; /* Pointer pointing to next
* vb2_buffer */
- enum v4l2_memory memory; /* This field keeps track of
- * type of buffer exchange
- * method user has selected */
struct v4l2_format fmt; /* Used to store the format */
struct vb2_queue buffer_queue; /* Buffer queue used in
* video-buf */
@@ -90,10 +83,6 @@ struct common_obj {
/* channel specific parameters */
struct mutex lock; /* lock used to access this
* structure */
- u32 io_usrs; /* number of users performing
- * IO */
- u8 started; /* Indicates whether streaming
- * started */
u32 ytop_off; /* offset of Y top from the
* starting of the buffer */
u32 ybtm_off; /* offset of Y bottom from the
@@ -103,7 +92,7 @@ struct common_obj {
u32 cbtm_off; /* offset of C bottom from the
* starting of the buffer */
/* Function pointer to set the addresses */
- void (*set_addr) (unsigned long, unsigned long,
+ void (*set_addr)(unsigned long, unsigned long,
unsigned long, unsigned long);
u32 height;
u32 width;
@@ -113,10 +102,6 @@ struct channel_obj {
/* V4l2 specific parameters */
struct video_device *video_dev; /* Identifies video device for
* this channel */
- struct v4l2_prio_state prio; /* Used to keep track of state of
- * the priority */
- atomic_t usrs; /* number of open instances of
- * the channel */
u32 field_id; /* Indicates id of the field
* which is being displayed */
u8 initialized; /* flag to indicate whether
@@ -130,19 +115,6 @@ struct channel_obj {
struct video_obj video;
};
-/* File handle structure */
-struct vpif_fh {
- struct channel_obj *channel; /* pointer to channel object for
- * opened device */
- u8 io_allowed[VPIF_NUMOBJECTS]; /* Indicates whether this file handle
- * is doing IO */
- enum v4l2_priority prio; /* Used to keep track priority of
- * this instance */
- u8 initialized; /* Used to keep track of whether this
- * file handle has initialized
- * channel or not */
-};
-
/* vpif device structure */
struct vpif_device {
struct v4l2_device v4l2_dev;
@@ -152,12 +124,4 @@ struct vpif_device {
struct vpif_display_config *config;
};
-struct vpif_config_params {
- u32 min_bufsize[VPIF_DISPLAY_NUM_CHANNELS];
- u32 channel_bufsize[VPIF_DISPLAY_NUM_CHANNELS];
- u8 numbuffers[VPIF_DISPLAY_NUM_CHANNELS];
- u32 video_limit[VPIF_DISPLAY_NUM_CHANNELS];
- u8 min_numbuffers;
-};
-
-#endif /* DAVINCIHD_DISPLAY_H */
+#endif /* VPIF_DISPLAY_H */
diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c
index d0ea94f58d6f..e434f1f03d7b 100644
--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c
+++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c
@@ -66,15 +66,13 @@ static int gsc_m2m_start_streaming(struct vb2_queue *q, unsigned int count)
return ret > 0 ? 0 : ret;
}
-static int gsc_m2m_stop_streaming(struct vb2_queue *q)
+static void gsc_m2m_stop_streaming(struct vb2_queue *q)
{
struct gsc_ctx *ctx = q->drv_priv;
__gsc_m2m_job_abort(ctx);
pm_runtime_put(&ctx->gsc_dev->pdev->dev);
-
- return 0;
}
void gsc_m2m_job_finish(struct gsc_ctx *ctx, int vb_state)
diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig
index e1b2ceba00c1..5dcaa0a80540 100644
--- a/drivers/media/platform/exynos4-is/Kconfig
+++ b/drivers/media/platform/exynos4-is/Kconfig
@@ -3,6 +3,7 @@ config VIDEO_SAMSUNG_EXYNOS4_IS
bool "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver"
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
depends on (PLAT_S5P || ARCH_EXYNOS)
+ depends on OF && COMMON_CLK
help
Say Y here to enable camera host interface devices for
Samsung S5P and EXYNOS SoC series.
@@ -17,7 +18,7 @@ config VIDEO_S5P_FIMC
depends on I2C
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
- select MFD_SYSCON if OF
+ select MFD_SYSCON
select VIDEO_EXYNOS4_IS_COMMON
help
This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC camera host
diff --git a/drivers/media/platform/exynos4-is/common.c b/drivers/media/platform/exynos4-is/common.c
index 0ec210b4da1d..0eb34ecb8ee4 100644
--- a/drivers/media/platform/exynos4-is/common.c
+++ b/drivers/media/platform/exynos4-is/common.c
@@ -10,7 +10,7 @@
*/
#include <linux/module.h>
-#include <media/s5p_fimc.h>
+#include <media/exynos-fimc.h>
#include "common.h"
/* Called with the media graph mutex held or entity->stream_count > 0. */
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index 92ae812abce2..3d2babd5067a 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -294,15 +294,15 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
return 0;
}
-static int stop_streaming(struct vb2_queue *q)
+static void stop_streaming(struct vb2_queue *q)
{
struct fimc_ctx *ctx = q->drv_priv;
struct fimc_dev *fimc = ctx->fimc_dev;
if (!fimc_capture_active(fimc))
- return -EINVAL;
+ return;
- return fimc_stop_capture(fimc, false);
+ fimc_stop_capture(fimc, false);
}
int fimc_capture_suspend(struct fimc_dev *fimc)
diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c
index 25dbf5b05a96..b70fd996d794 100644
--- a/drivers/media/platform/exynos4-is/fimc-core.c
+++ b/drivers/media/platform/exynos4-is/fimc-core.c
@@ -56,8 +56,8 @@ static struct fimc_fmt fimc_formats[] = {
.colplanes = 1,
.flags = FMT_FLAGS_M2M,
}, {
- .name = "ARGB8888, 32 bpp",
- .fourcc = V4L2_PIX_FMT_RGB32,
+ .name = "BGRA8888, 32 bpp",
+ .fourcc = V4L2_PIX_FMT_BGR32,
.depth = { 32 },
.color = FIMC_FMT_RGB888,
.memplanes = 1,
@@ -450,7 +450,7 @@ void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
bool pix_hoff = ctx->fimc_dev->drv_data->dma_pix_hoff;
u32 i, depth = 0;
- for (i = 0; i < f->fmt->colplanes; i++)
+ for (i = 0; i < f->fmt->memplanes; i++)
depth += f->fmt->depth[i];
f->dma_offset.y_h = f->offs_h;
diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h
index 1790fb4e32ea..6c75c6ced1f7 100644
--- a/drivers/media/platform/exynos4-is/fimc-core.h
+++ b/drivers/media/platform/exynos4-is/fimc-core.h
@@ -27,7 +27,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-mem2mem.h>
#include <media/v4l2-mediabus.h>
-#include <media/s5p_fimc.h>
+#include <media/exynos-fimc.h>
#define dbg(fmt, args...) \
pr_debug("%s:%d: " fmt "\n", __func__, __LINE__, ##args)
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c
index 128b73b6cce2..5476dce3ad29 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/exynos4-is/fimc-is.c
@@ -367,6 +367,9 @@ static void fimc_is_free_cpu_memory(struct fimc_is *is)
{
struct device *dev = &is->pdev->dev;
+ if (is->memory.vaddr == NULL)
+ return;
+
dma_free_coherent(dev, is->memory.size, is->memory.vaddr,
is->memory.paddr);
}
diff --git a/drivers/media/platform/exynos4-is/fimc-isp-video.c b/drivers/media/platform/exynos4-is/fimc-isp-video.c
index e92b4e115adb..93f9cf2ebcd6 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp-video.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp-video.c
@@ -30,7 +30,7 @@
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
-#include <media/s5p_fimc.h>
+#include <media/exynos-fimc.h>
#include "common.h"
#include "media-dev.h"
@@ -125,7 +125,7 @@ static int isp_video_capture_start_streaming(struct vb2_queue *q,
return ret;
}
-static int isp_video_capture_stop_streaming(struct vb2_queue *q)
+static void isp_video_capture_stop_streaming(struct vb2_queue *q)
{
struct fimc_isp *isp = vb2_get_drv_priv(q);
struct fimc_is *is = fimc_isp_to_is(isp);
@@ -134,7 +134,7 @@ static int isp_video_capture_stop_streaming(struct vb2_queue *q)
ret = fimc_pipeline_call(&isp->video_capture.ve, set_stream, 0);
if (ret < 0)
- return ret;
+ return;
dma->cmd = DMA_OUTPUT_COMMAND_DISABLE;
dma->notify_dma_done = DMA_OUTPUT_NOTIFY_DMA_DONE_DISABLE;
@@ -155,7 +155,6 @@ static int isp_video_capture_stop_streaming(struct vb2_queue *q)
clear_bit(ST_ISP_VID_CAP_STREAMING, &isp->state);
isp->video_capture.buf_count = 0;
- return 0;
}
static int isp_video_capture_buffer_prepare(struct vb2_buffer *vb)
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.h b/drivers/media/platform/exynos4-is/fimc-isp.h
index 4dc55a18d978..b99be09b49fc 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp.h
+++ b/drivers/media/platform/exynos4-is/fimc-isp.h
@@ -24,7 +24,7 @@
#include <media/videobuf2-core.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mediabus.h>
-#include <media/s5p_fimc.h>
+#include <media/exynos-fimc.h>
extern int fimc_isp_debug;
diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.c b/drivers/media/platform/exynos4-is/fimc-lite-reg.c
index d0dc7ee04452..bc3ec7d25a32 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite-reg.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.c
@@ -12,7 +12,7 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/io.h>
-#include <media/s5p_fimc.h>
+#include <media/exynos-fimc.h>
#include "fimc-lite-reg.h"
#include "fimc-lite.h"
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index 3ad660b55b6b..a97d2352f1d7 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -30,7 +30,7 @@
#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
-#include <media/s5p_fimc.h>
+#include <media/exynos-fimc.h>
#include "common.h"
#include "fimc-core.h"
@@ -350,14 +350,14 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
return 0;
}
-static int stop_streaming(struct vb2_queue *q)
+static void stop_streaming(struct vb2_queue *q)
{
struct fimc_lite *fimc = q->drv_priv;
if (!fimc_lite_active(fimc))
- return -EINVAL;
+ return;
- return fimc_lite_stop_capture(fimc, false);
+ fimc_lite_stop_capture(fimc, false);
}
static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.h b/drivers/media/platform/exynos4-is/fimc-lite.h
index 7428b2d22b52..ea19dc7be63e 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.h
+++ b/drivers/media/platform/exynos4-is/fimc-lite.h
@@ -23,7 +23,7 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-mediabus.h>
-#include <media/s5p_fimc.h>
+#include <media/exynos-fimc.h>
#define FIMC_LITE_DRV_NAME "exynos-fimc-lite"
#define FLITE_CLK_NAME "flite"
diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c
index 36971d915b53..0ad1b6f84a27 100644
--- a/drivers/media/platform/exynos4-is/fimc-m2m.c
+++ b/drivers/media/platform/exynos4-is/fimc-m2m.c
@@ -85,7 +85,7 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
return ret > 0 ? 0 : ret;
}
-static int stop_streaming(struct vb2_queue *q)
+static void stop_streaming(struct vb2_queue *q)
{
struct fimc_ctx *ctx = q->drv_priv;
int ret;
@@ -95,7 +95,6 @@ static int stop_streaming(struct vb2_queue *q)
fimc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR);
pm_runtime_put(&ctx->fimc_dev->pdev->dev);
- return 0;
}
static void fimc_device_run(void *priv)
@@ -197,7 +196,7 @@ static int fimc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
*num_planes = f->fmt->memplanes;
for (i = 0; i < f->fmt->memplanes; i++) {
- sizes[i] = (f->f_width * f->f_height * f->fmt->depth[i]) / 8;
+ sizes[i] = f->payload[i];
allocators[i] = ctx->fimc_dev->alloc_ctx;
}
return 0;
@@ -342,7 +341,7 @@ static void __set_frame_format(struct fimc_frame *frame, struct fimc_fmt *fmt,
{
int i;
- for (i = 0; i < fmt->colplanes; i++) {
+ for (i = 0; i < fmt->memplanes; i++) {
frame->bytesperline[i] = pixm->plane_fmt[i].bytesperline;
frame->payload[i] = pixm->plane_fmt[i].sizeimage;
}
@@ -461,7 +460,7 @@ static int fimc_m2m_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
else
halign = ffs(fimc->variant->min_vsize_align) - 1;
- for (i = 0; i < f->fmt->colplanes; i++)
+ for (i = 0; i < f->fmt->memplanes; i++)
depth += f->fmt->depth[i];
v4l_bound_align_image(&cr->c.width, min_size, f->o_width,
diff --git a/drivers/media/platform/exynos4-is/fimc-reg.c b/drivers/media/platform/exynos4-is/fimc-reg.c
index 1db8cb4c46ef..2d77fd8f440a 100644
--- a/drivers/media/platform/exynos4-is/fimc-reg.c
+++ b/drivers/media/platform/exynos4-is/fimc-reg.c
@@ -13,7 +13,7 @@
#include <linux/io.h>
#include <linux/regmap.h>
-#include <media/s5p_fimc.h>
+#include <media/exynos-fimc.h>
#include "media-dev.h"
#include "fimc-reg.h"
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index e62211a80f0e..344718df5c62 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -31,7 +31,7 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-of.h>
#include <media/media-device.h>
-#include <media/s5p_fimc.h>
+#include <media/exynos-fimc.h>
#include "media-dev.h"
#include "fimc-core.h"
@@ -39,10 +39,6 @@
#include "fimc-lite.h"
#include "mipi-csis.h"
-static int __fimc_md_set_camclk(struct fimc_md *fmd,
- struct fimc_source_info *si,
- bool on);
-
/* Set up image sensor subdev -> FIMC capture node notifications. */
static void __setup_sensor_notification(struct fimc_md *fmd,
struct v4l2_subdev *sensor,
@@ -223,17 +219,10 @@ static int __fimc_pipeline_open(struct exynos_media_pipeline *ep,
return ret;
}
- ret = fimc_md_set_camclk(sd, true);
- if (ret < 0)
- goto err_wbclk;
-
ret = fimc_pipeline_s_power(p, 1);
if (!ret)
return 0;
- fimc_md_set_camclk(sd, false);
-
-err_wbclk:
if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP])
clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]);
@@ -259,7 +248,6 @@ static int __fimc_pipeline_close(struct exynos_media_pipeline *ep)
}
ret = fimc_pipeline_s_power(p, 0);
- fimc_md_set_camclk(sd, false);
fmd = entity_to_fimc_mdev(&sd->entity);
@@ -337,75 +325,14 @@ static void fimc_md_pipelines_free(struct fimc_md *fmd)
}
}
-/*
- * Sensor subdevice helper functions
- */
-static struct v4l2_subdev *fimc_md_register_sensor(struct fimc_md *fmd,
- struct fimc_source_info *si)
-{
- struct i2c_adapter *adapter;
- struct v4l2_subdev *sd = NULL;
-
- if (!si || !fmd)
- return NULL;
- /*
- * If FIMC bus type is not Writeback FIFO assume it is same
- * as sensor_bus_type.
- */
- si->fimc_bus_type = si->sensor_bus_type;
-
- adapter = i2c_get_adapter(si->i2c_bus_num);
- if (!adapter) {
- v4l2_warn(&fmd->v4l2_dev,
- "Failed to get I2C adapter %d, deferring probe\n",
- si->i2c_bus_num);
- return ERR_PTR(-EPROBE_DEFER);
- }
- sd = v4l2_i2c_new_subdev_board(&fmd->v4l2_dev, adapter,
- si->board_info, NULL);
- if (IS_ERR_OR_NULL(sd)) {
- i2c_put_adapter(adapter);
- v4l2_warn(&fmd->v4l2_dev,
- "Failed to acquire subdev %s, deferring probe\n",
- si->board_info->type);
- return ERR_PTR(-EPROBE_DEFER);
- }
- v4l2_set_subdev_hostdata(sd, si);
- sd->grp_id = GRP_ID_SENSOR;
-
- v4l2_info(&fmd->v4l2_dev, "Registered sensor subdevice %s\n",
- sd->name);
- return sd;
-}
-
-static void fimc_md_unregister_sensor(struct v4l2_subdev *sd)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct i2c_adapter *adapter;
-
- if (!client || client->dev.of_node)
- return;
-
- v4l2_device_unregister_subdev(sd);
-
- adapter = client->adapter;
- i2c_unregister_device(client);
- if (adapter)
- i2c_put_adapter(adapter);
-}
-
-#ifdef CONFIG_OF
/* Parse port node and register as a sub-device any sensor specified there. */
static int fimc_md_parse_port_node(struct fimc_md *fmd,
struct device_node *port,
unsigned int index)
{
+ struct fimc_source_info *pd = &fmd->sensor[index].pdata;
struct device_node *rem, *ep, *np;
- struct fimc_source_info *pd;
struct v4l2_of_endpoint endpoint;
- u32 val;
-
- pd = &fmd->sensor[index].pdata;
/* Assume here a port node can have only one endpoint node. */
ep = of_get_next_child(port, NULL);
@@ -425,20 +352,6 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
ep->full_name);
return 0;
}
- if (!of_property_read_u32(rem, "samsung,camclk-out", &val))
- pd->clk_id = val;
-
- if (!of_property_read_u32(rem, "clock-frequency", &val))
- pd->clk_frequency = val;
- else
- pd->clk_frequency = DEFAULT_SENSOR_CLK_FREQ;
-
- if (pd->clk_frequency == 0) {
- v4l2_err(&fmd->v4l2_dev, "Wrong clock frequency at node %s\n",
- rem->full_name);
- of_node_put(rem);
- return -EINVAL;
- }
if (fimc_input_is_parallel(endpoint.base.port)) {
if (endpoint.bus_type == V4L2_MBUS_PARALLEL)
@@ -485,14 +398,26 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
}
/* Register all SoC external sub-devices */
-static int fimc_md_of_sensors_register(struct fimc_md *fmd,
- struct device_node *np)
+static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
{
struct device_node *parent = fmd->pdev->dev.of_node;
struct device_node *node, *ports;
int index = 0;
int ret;
+ /*
+ * Runtime resume one of the FIMC entities to make sure
+ * the sclk_cam clocks are not globally disabled.
+ */
+ if (!fmd->pmf)
+ return -ENXIO;
+
+ ret = pm_runtime_get_sync(fmd->pmf);
+ if (ret < 0)
+ return ret;
+
+ fmd->num_sensors = 0;
+
/* Attach sensors linked to MIPI CSI-2 receivers */
for_each_available_child_of_node(parent, node) {
struct device_node *port;
@@ -506,14 +431,14 @@ static int fimc_md_of_sensors_register(struct fimc_md *fmd,
ret = fimc_md_parse_port_node(fmd, port, index);
if (ret < 0)
- return ret;
+ goto rpm_put;
index++;
}
/* Attach sensors listed in the parallel-ports node */
ports = of_get_child_by_name(parent, "parallel-ports");
if (!ports)
- return 0;
+ goto rpm_put;
for_each_child_of_node(ports, node) {
ret = fimc_md_parse_port_node(fmd, node, index);
@@ -521,8 +446,9 @@ static int fimc_md_of_sensors_register(struct fimc_md *fmd,
break;
index++;
}
-
- return 0;
+rpm_put:
+ pm_runtime_put(fmd->pmf);
+ return ret;
}
static int __of_get_csis_id(struct device_node *np)
@@ -535,68 +461,10 @@ static int __of_get_csis_id(struct device_node *np)
of_property_read_u32(np, "reg", &reg);
return reg - FIMC_INPUT_MIPI_CSI2_0;
}
-#else
-#define fimc_md_of_sensors_register(fmd, np) (-ENOSYS)
-#define __of_get_csis_id(np) (-ENOSYS)
-#endif
-
-static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
-{
- struct s5p_platform_fimc *pdata = fmd->pdev->dev.platform_data;
- struct device_node *of_node = fmd->pdev->dev.of_node;
- int num_clients = 0;
- int ret, i;
-
- /*
- * Runtime resume one of the FIMC entities to make sure
- * the sclk_cam clocks are not globally disabled.
- */
- if (!fmd->pmf)
- return -ENXIO;
-
- ret = pm_runtime_get_sync(fmd->pmf);
- if (ret < 0)
- return ret;
-
- if (of_node) {
- fmd->num_sensors = 0;
- ret = fimc_md_of_sensors_register(fmd, of_node);
- } else if (pdata) {
- WARN_ON(pdata->num_clients > ARRAY_SIZE(fmd->sensor));
- num_clients = min_t(u32, pdata->num_clients,
- ARRAY_SIZE(fmd->sensor));
- fmd->num_sensors = num_clients;
-
- for (i = 0; i < num_clients; i++) {
- struct fimc_sensor_info *si = &fmd->sensor[i];
- struct v4l2_subdev *sd;
-
- si->pdata = pdata->source_info[i];
- ret = __fimc_md_set_camclk(fmd, &si->pdata, true);
- if (ret)
- break;
- sd = fimc_md_register_sensor(fmd, &si->pdata);
- ret = __fimc_md_set_camclk(fmd, &si->pdata, false);
-
- if (IS_ERR(sd)) {
- si->subdev = NULL;
- ret = PTR_ERR(sd);
- break;
- }
- si->subdev = sd;
- if (ret)
- break;
- }
- }
-
- pm_runtime_put(fmd->pmf);
- return ret;
-}
/*
* MIPI-CSIS, FIMC and FIMC-LITE platform devices registration.
*/
-
static int register_fimc_lite_entity(struct fimc_md *fmd,
struct fimc_lite *fimc_lite)
{
@@ -753,35 +621,9 @@ dev_unlock:
return ret;
}
-static int fimc_md_pdev_match(struct device *dev, void *data)
-{
- struct platform_device *pdev = to_platform_device(dev);
- int plat_entity = -1;
- int ret;
- char *p;
-
- if (!get_device(dev))
- return -ENODEV;
-
- if (!strcmp(pdev->name, CSIS_DRIVER_NAME)) {
- plat_entity = IDX_CSIS;
- } else {
- p = strstr(pdev->name, "fimc");
- if (p && *(p + 4) == 0)
- plat_entity = IDX_FIMC;
- }
-
- if (plat_entity >= 0)
- ret = fimc_md_register_platform_entity(data, pdev,
- plat_entity);
- put_device(dev);
- return 0;
-}
-
/* Register FIMC, FIMC-LITE and CSIS media entities */
-#ifdef CONFIG_OF
-static int fimc_md_register_of_platform_entities(struct fimc_md *fmd,
- struct device_node *parent)
+static int fimc_md_register_platform_entities(struct fimc_md *fmd,
+ struct device_node *parent)
{
struct device_node *node;
int ret = 0;
@@ -815,9 +657,6 @@ static int fimc_md_register_of_platform_entities(struct fimc_md *fmd,
return ret;
}
-#else
-#define fimc_md_register_of_platform_entities(fmd, node) (-ENOSYS)
-#endif
static void fimc_md_unregister_entities(struct fimc_md *fmd)
{
@@ -845,14 +684,6 @@ static void fimc_md_unregister_entities(struct fimc_md *fmd)
v4l2_device_unregister_subdev(fmd->csis[i].sd);
fmd->csis[i].sd = NULL;
}
- if (fmd->pdev->dev.of_node == NULL) {
- for (i = 0; i < fmd->num_sensors; i++) {
- if (fmd->sensor[i].subdev == NULL)
- continue;
- fimc_md_unregister_sensor(fmd->sensor[i].subdev);
- fmd->sensor[i].subdev = NULL;
- }
- }
if (fmd->fimc_is)
v4l2_device_unregister_subdev(&fmd->fimc_is->isp.subdev);
@@ -1137,7 +968,7 @@ static void fimc_md_put_clocks(struct fimc_md *fmd)
static int fimc_md_get_clocks(struct fimc_md *fmd)
{
- struct device *dev = NULL;
+ struct device *dev = &fmd->pdev->dev;
char clk_name[32];
struct clk *clock;
int i, ret = 0;
@@ -1145,16 +976,12 @@ static int fimc_md_get_clocks(struct fimc_md *fmd)
for (i = 0; i < FIMC_MAX_CAMCLKS; i++)
fmd->camclk[i].clock = ERR_PTR(-EINVAL);
- if (fmd->pdev->dev.of_node)
- dev = &fmd->pdev->dev;
-
for (i = 0; i < FIMC_MAX_CAMCLKS; i++) {
snprintf(clk_name, sizeof(clk_name), "sclk_cam%u", i);
clock = clk_get(dev, clk_name);
if (IS_ERR(clock)) {
- dev_err(&fmd->pdev->dev, "Failed to get clock: %s\n",
- clk_name);
+ dev_err(dev, "Failed to get clock: %s\n", clk_name);
ret = PTR_ERR(clock);
break;
}
@@ -1188,86 +1015,6 @@ static int fimc_md_get_clocks(struct fimc_md *fmd)
return ret;
}
-static int __fimc_md_set_camclk(struct fimc_md *fmd,
- struct fimc_source_info *si,
- bool on)
-{
- struct fimc_camclk_info *camclk;
- int ret = 0;
-
- /*
- * When device tree is used the sensor drivers are supposed to
- * control the clock themselves. This whole function will be
- * removed once S5PV210 platform is converted to the device tree.
- */
- if (fmd->pdev->dev.of_node)
- return 0;
-
- if (WARN_ON(si->clk_id >= FIMC_MAX_CAMCLKS) || !fmd || !fmd->pmf)
- return -EINVAL;
-
- camclk = &fmd->camclk[si->clk_id];
-
- dbg("camclk %d, f: %lu, use_count: %d, on: %d",
- si->clk_id, si->clk_frequency, camclk->use_count, on);
-
- if (on) {
- if (camclk->use_count > 0 &&
- camclk->frequency != si->clk_frequency)
- return -EINVAL;
-
- if (camclk->use_count++ == 0) {
- clk_set_rate(camclk->clock, si->clk_frequency);
- camclk->frequency = si->clk_frequency;
- ret = pm_runtime_get_sync(fmd->pmf);
- if (ret < 0)
- return ret;
- ret = clk_prepare_enable(camclk->clock);
- dbg("Enabled camclk %d: f: %lu", si->clk_id,
- clk_get_rate(camclk->clock));
- }
- return ret;
- }
-
- if (WARN_ON(camclk->use_count == 0))
- return 0;
-
- if (--camclk->use_count == 0) {
- clk_disable_unprepare(camclk->clock);
- pm_runtime_put(fmd->pmf);
- dbg("Disabled camclk %d", si->clk_id);
- }
- return ret;
-}
-
-/**
- * fimc_md_set_camclk - peripheral sensor clock setup
- * @sd: sensor subdev to configure sclk_cam clock for
- * @on: 1 to enable or 0 to disable the clock
- *
- * There are 2 separate clock outputs available in the SoC for external
- * image processors. These clocks are shared between all registered FIMC
- * devices to which sensors can be attached, either directly or through
- * the MIPI CSI receiver. The clock is allowed here to be used by
- * multiple sensors concurrently if they use same frequency.
- * This function should only be called when the graph mutex is held.
- */
-int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on)
-{
- struct fimc_source_info *si = v4l2_get_subdev_hostdata(sd);
- struct fimc_md *fmd = entity_to_fimc_mdev(&sd->entity);
-
- /*
- * If there is a clock provider registered the sensors will
- * handle their clock themselves, no need to control it on
- * the host interface side.
- */
- if (fmd->clk_provider.num_clocks > 0)
- return 0;
-
- return __fimc_md_set_camclk(fmd, si, on);
-}
-
static int __fimc_md_modify_pipeline(struct media_entity *entity, bool enable)
{
struct exynos_video_entity *ve;
@@ -1426,7 +1173,6 @@ static int fimc_md_get_pinctrl(struct fimc_md *fmd)
return 0;
}
-#ifdef CONFIG_OF
static int cam_clk_prepare(struct clk_hw *hw)
{
struct cam_clk *camclk = to_cam_clk(hw);
@@ -1518,10 +1264,6 @@ err:
fimc_md_unregister_clk_provider(fmd);
return ret;
}
-#else
-#define fimc_md_register_clk_provider(fmd) (0)
-#define fimc_md_unregister_clk_provider(fmd) (0)
-#endif
static int subdev_notifier_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *subdev,
@@ -1585,8 +1327,8 @@ static int fimc_md_probe(struct platform_device *pdev)
return -ENOMEM;
spin_lock_init(&fmd->slock);
- fmd->pdev = pdev;
INIT_LIST_HEAD(&fmd->pipelines);
+ fmd->pdev = pdev;
strlcpy(fmd->media_dev.model, "SAMSUNG S5P FIMC",
sizeof(fmd->media_dev.model));
@@ -1599,6 +1341,7 @@ static int fimc_md_probe(struct platform_device *pdev)
strlcpy(v4l2_dev->name, "s5p-fimc-md", sizeof(v4l2_dev->name));
fmd->use_isp = fimc_md_is_isp_available(dev->of_node);
+ fmd->user_subdev_api = true;
ret = v4l2_device_register(dev, &fmd->v4l2_dev);
if (ret < 0) {
@@ -1616,8 +1359,6 @@ static int fimc_md_probe(struct platform_device *pdev)
if (ret)
goto err_md;
- fmd->user_subdev_api = (dev->of_node != NULL);
-
ret = fimc_md_get_pinctrl(fmd);
if (ret < 0) {
if (ret != EPROBE_DEFER)
@@ -1630,22 +1371,16 @@ static int fimc_md_probe(struct platform_device *pdev)
/* Protect the media graph while we're registering entities */
mutex_lock(&fmd->media_dev.graph_mutex);
- if (dev->of_node)
- ret = fimc_md_register_of_platform_entities(fmd, dev->of_node);
- else
- ret = bus_for_each_dev(&platform_bus_type, NULL, fmd,
- fimc_md_pdev_match);
+ ret = fimc_md_register_platform_entities(fmd, dev->of_node);
if (ret) {
mutex_unlock(&fmd->media_dev.graph_mutex);
goto err_clk;
}
- if (dev->platform_data || dev->of_node) {
- ret = fimc_md_register_sensor_entities(fmd);
- if (ret) {
- mutex_unlock(&fmd->media_dev.graph_mutex);
- goto err_m_ent;
- }
+ ret = fimc_md_register_sensor_entities(fmd);
+ if (ret) {
+ mutex_unlock(&fmd->media_dev.graph_mutex);
+ goto err_m_ent;
}
mutex_unlock(&fmd->media_dev.graph_mutex);
diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h
index ee1e2519f728..03214541f149 100644
--- a/drivers/media/platform/exynos4-is/media-dev.h
+++ b/drivers/media/platform/exynos4-is/media-dev.h
@@ -19,7 +19,7 @@
#include <media/media-entity.h>
#include <media/v4l2-device.h>
#include <media/v4l2-subdev.h>
-#include <media/s5p_fimc.h>
+#include <media/exynos-fimc.h>
#include "fimc-core.h"
#include "fimc-lite.h"
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index 3678ba59725c..ae54ef5f535d 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -22,14 +22,13 @@
#include <linux/of.h>
#include <linux/of_graph.h>
#include <linux/phy/phy.h>
-#include <linux/platform_data/mipi-csis.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/videodev2.h>
-#include <media/s5p_fimc.h>
+#include <media/exynos-fimc.h>
#include <media/v4l2-of.h>
#include <media/v4l2-subdev.h>
@@ -730,26 +729,6 @@ static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int s5pcsis_get_platform_data(struct platform_device *pdev,
- struct csis_state *state)
-{
- struct s5p_platform_mipi_csis *pdata = pdev->dev.platform_data;
-
- if (pdata == NULL) {
- dev_err(&pdev->dev, "Platform data not specified\n");
- return -EINVAL;
- }
-
- state->clk_frequency = pdata->clk_rate;
- state->num_lanes = pdata->lanes;
- state->hs_settle = pdata->hs_settle;
- state->index = max(0, pdev->id);
- state->max_num_lanes = state->index ? CSIS1_MAX_LANES :
- CSIS0_MAX_LANES;
- return 0;
-}
-
-#ifdef CONFIG_OF
static int s5pcsis_parse_dt(struct platform_device *pdev,
struct csis_state *state)
{
@@ -787,9 +766,6 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
return 0;
}
-#else
-#define s5pcsis_parse_dt(pdev, state) (-ENOSYS)
-#endif
static int s5pcsis_pm_resume(struct device *dev, bool runtime);
static const struct of_device_id s5pcsis_of_match[];
@@ -812,19 +788,14 @@ static int s5pcsis_probe(struct platform_device *pdev)
spin_lock_init(&state->slock);
state->pdev = pdev;
- if (dev->of_node) {
- of_id = of_match_node(s5pcsis_of_match, dev->of_node);
- if (WARN_ON(of_id == NULL))
- return -EINVAL;
-
- drv_data = of_id->data;
- state->interrupt_mask = drv_data->interrupt_mask;
+ of_id = of_match_node(s5pcsis_of_match, dev->of_node);
+ if (WARN_ON(of_id == NULL))
+ return -EINVAL;
- ret = s5pcsis_parse_dt(pdev, state);
- } else {
- ret = s5pcsis_get_platform_data(pdev, state);
- }
+ drv_data = of_id->data;
+ state->interrupt_mask = drv_data->interrupt_mask;
+ ret = s5pcsis_parse_dt(pdev, state);
if (ret < 0)
return ret;
diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c
index dbf0ce38a8e7..d5dc198502ef 100644
--- a/drivers/media/platform/fsl-viu.c
+++ b/drivers/media/platform/fsl-viu.c
@@ -964,7 +964,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
struct viu_fh *fh = priv;
fh->dev->std = id;
- decoder_call(fh->dev, core, s_std, id);
+ decoder_call(fh->dev, video, s_std, id);
return 0;
}
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index 8b34c485be79..be4b51212106 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -1156,7 +1156,7 @@ static int mcam_vb_start_streaming(struct vb2_queue *vq, unsigned int count)
return mcam_read_setup(cam);
}
-static int mcam_vb_stop_streaming(struct vb2_queue *vq)
+static void mcam_vb_stop_streaming(struct vb2_queue *vq)
{
struct mcam_camera *cam = vb2_get_drv_priv(vq);
unsigned long flags;
@@ -1164,10 +1164,10 @@ static int mcam_vb_stop_streaming(struct vb2_queue *vq)
if (cam->state == S_BUFWAIT) {
/* They never gave us buffers */
cam->state = S_IDLE;
- return 0;
+ return;
}
if (cam->state != S_STREAMING)
- return -EINVAL;
+ return;
mcam_ctlr_stop_dma(cam);
/*
* Reset the CCIC PHY after stopping streaming,
@@ -1182,7 +1182,6 @@ static int mcam_vb_stop_streaming(struct vb2_queue *vq)
spin_lock_irqsave(&cam->dev_lock, flags);
INIT_LIST_HEAD(&cam->buffers);
spin_unlock_irqrestore(&cam->dev_lock, flags);
- return 0;
}
diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/mem2mem_testdev.c
index 4f3096b17066..0714070ed7fa 100644
--- a/drivers/media/platform/mem2mem_testdev.c
+++ b/drivers/media/platform/mem2mem_testdev.c
@@ -787,7 +787,7 @@ static int m2mtest_start_streaming(struct vb2_queue *q, unsigned count)
return 0;
}
-static int m2mtest_stop_streaming(struct vb2_queue *q)
+static void m2mtest_stop_streaming(struct vb2_queue *q)
{
struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
struct vb2_buffer *vb;
@@ -799,12 +799,11 @@ static int m2mtest_stop_streaming(struct vb2_queue *q)
else
vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
if (vb == NULL)
- return 0;
+ return;
spin_lock_irqsave(&ctx->dev->irqlock, flags);
v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
spin_unlock_irqrestore(&ctx->dev->irqlock, flags);
}
- return 0;
}
static struct vb2_ops m2mtest_qops = {
diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c
index 0b7480e82142..fa8f7cabe364 100644
--- a/drivers/media/platform/mx2_emmaprp.c
+++ b/drivers/media/platform/mx2_emmaprp.c
@@ -207,10 +207,8 @@ struct emmaprp_dev {
struct mutex dev_mutex;
spinlock_t irqlock;
- int irq_emma;
void __iomem *base_emma;
struct clk *clk_emma_ahb, *clk_emma_ipg;
- struct resource *res_emma;
struct v4l2_m2m_dev *m2m_dev;
struct vb2_alloc_ctx *alloc_ctx;
@@ -901,9 +899,8 @@ static int emmaprp_probe(struct platform_device *pdev)
{
struct emmaprp_dev *pcdev;
struct video_device *vfd;
- struct resource *res_emma;
- int irq_emma;
- int ret;
+ struct resource *res;
+ int irq, ret;
pcdev = devm_kzalloc(&pdev->dev, sizeof(*pcdev), GFP_KERNEL);
if (!pcdev)
@@ -920,12 +917,10 @@ static int emmaprp_probe(struct platform_device *pdev)
if (IS_ERR(pcdev->clk_emma_ahb))
return PTR_ERR(pcdev->clk_emma_ahb);
- irq_emma = platform_get_irq(pdev, 0);
- res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (irq_emma < 0 || res_emma == NULL) {
- dev_err(&pdev->dev, "Missing platform resources data\n");
- return -ENODEV;
- }
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pcdev->base_emma = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pcdev->base_emma))
+ return PTR_ERR(pcdev->base_emma);
ret = v4l2_device_register(&pdev->dev, &pcdev->v4l2_dev);
if (ret)
@@ -952,20 +947,11 @@ static int emmaprp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pcdev);
- pcdev->base_emma = devm_ioremap_resource(&pdev->dev, res_emma);
- if (IS_ERR(pcdev->base_emma)) {
- ret = PTR_ERR(pcdev->base_emma);
- goto rel_vdev;
- }
-
- pcdev->irq_emma = irq_emma;
- pcdev->res_emma = res_emma;
-
- if (devm_request_irq(&pdev->dev, pcdev->irq_emma, emmaprp_irq,
- 0, MEM2MEM_NAME, pcdev) < 0) {
- ret = -ENODEV;
+ irq = platform_get_irq(pdev, 0);
+ ret = devm_request_irq(&pdev->dev, irq, emmaprp_irq, 0,
+ dev_name(&pdev->dev), pcdev);
+ if (ret)
goto rel_vdev;
- }
pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
if (IS_ERR(pcdev->alloc_ctx)) {
@@ -999,6 +985,8 @@ rel_vdev:
unreg_dev:
v4l2_device_unregister(&pcdev->v4l2_dev);
+ mutex_destroy(&pcdev->dev_mutex);
+
return ret;
}
@@ -1012,6 +1000,7 @@ static int emmaprp_remove(struct platform_device *pdev)
v4l2_m2m_release(pcdev->m2m_dev);
vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
v4l2_device_unregister(&pcdev->v4l2_dev);
+ mutex_destroy(&pcdev->dev_mutex);
return 0;
}
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index 4e4d1631e042..deba425e3d8f 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -435,10 +435,10 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
return 0;
}
-static int stop_streaming(struct vb2_queue *vq)
+static void stop_streaming(struct vb2_queue *vq)
{
struct camif_vp *vp = vb2_get_drv_priv(vq);
- return camif_stop_capture(vp);
+ camif_stop_capture(vp);
}
static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *pfmt,
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 8a18972012f7..0dcb796ecad9 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -192,8 +192,7 @@ static struct s5p_jpeg_fmt sjpeg_formats[] = {
.colplanes = 2,
.h_align = 4,
.v_align = 4,
- .flags = SJPEG_FMT_FLAG_ENC_OUTPUT |
- SJPEG_FMT_FLAG_DEC_CAPTURE |
+ .flags = SJPEG_FMT_FLAG_DEC_CAPTURE |
SJPEG_FMT_FLAG_S5P |
SJPEG_FMT_NON_RGB,
.subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
@@ -959,7 +958,7 @@ static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
u32 pixelformat, unsigned int fmt_type)
{
- unsigned int k, fmt_flag, ver_flag;
+ unsigned int k, fmt_flag;
if (ctx->mode == S5P_JPEG_ENCODE)
fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
@@ -970,16 +969,11 @@ static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
SJPEG_FMT_FLAG_DEC_OUTPUT :
SJPEG_FMT_FLAG_DEC_CAPTURE;
- if (ctx->jpeg->variant->version == SJPEG_S5P)
- ver_flag = SJPEG_FMT_FLAG_S5P;
- else
- ver_flag = SJPEG_FMT_FLAG_EXYNOS4;
-
for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) {
struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k];
if (fmt->fourcc == pixelformat &&
fmt->flags & fmt_flag &&
- fmt->flags & ver_flag) {
+ fmt->flags & ctx->jpeg->variant->fmt_ver_flag) {
return fmt;
}
}
@@ -1069,15 +1063,17 @@ static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
return -EINVAL;
}
+ if ((ctx->jpeg->variant->version != SJPEG_EXYNOS4) ||
+ (ctx->mode != S5P_JPEG_DECODE))
+ goto exit;
+
/*
* The exynos4x12 device requires resulting YUV image
* subsampling not to be lower than the input jpeg subsampling.
* If this requirement is not met then downgrade the requested
* capture format to the one with subsampling equal to the input jpeg.
*/
- if ((ctx->jpeg->variant->version != SJPEG_S5P) &&
- (ctx->mode == S5P_JPEG_DECODE) &&
- (fmt->flags & SJPEG_FMT_NON_RGB) &&
+ if ((fmt->flags & SJPEG_FMT_NON_RGB) &&
(fmt->subsampling < ctx->subsampling)) {
ret = s5p_jpeg_adjust_fourcc_to_subsampling(ctx->subsampling,
fmt->fourcc,
@@ -1090,6 +1086,23 @@ static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
FMT_TYPE_CAPTURE);
}
+ /*
+ * Decompression of a JPEG file with 4:2:0 subsampling and odd
+ * width to the YUV 4:2:0 compliant formats produces a raw image
+ * with broken luma component. Adjust capture format to RGB565
+ * in such a case.
+ */
+ if (ctx->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_420 &&
+ (ctx->out_q.w & 1) &&
+ (pix->pixelformat == V4L2_PIX_FMT_NV12 ||
+ pix->pixelformat == V4L2_PIX_FMT_NV21 ||
+ pix->pixelformat == V4L2_PIX_FMT_YUV420)) {
+ pix->pixelformat = V4L2_PIX_FMT_RGB565;
+ fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
+ FMT_TYPE_CAPTURE);
+ }
+
+exit:
return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
}
@@ -1111,6 +1124,32 @@ static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
}
+static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx,
+ struct v4l2_format *f,
+ int fmt_depth)
+{
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ u32 pix_fmt = f->fmt.pix.pixelformat;
+ int w = pix->width, h = pix->height, wh_align;
+
+ if (pix_fmt == V4L2_PIX_FMT_RGB32 ||
+ pix_fmt == V4L2_PIX_FMT_NV24 ||
+ pix_fmt == V4L2_PIX_FMT_NV42 ||
+ pix_fmt == V4L2_PIX_FMT_NV12 ||
+ pix_fmt == V4L2_PIX_FMT_NV21 ||
+ pix_fmt == V4L2_PIX_FMT_YUV420)
+ wh_align = 4;
+ else
+ wh_align = 1;
+
+ jpeg_bound_align_image(&w, S5P_JPEG_MIN_WIDTH,
+ S5P_JPEG_MAX_WIDTH, wh_align,
+ &h, S5P_JPEG_MIN_HEIGHT,
+ S5P_JPEG_MAX_HEIGHT, wh_align);
+
+ return w * h * fmt_depth >> 3;
+}
+
static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
{
struct vb2_queue *vq;
@@ -1137,10 +1176,24 @@ static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
q_data->w = pix->width;
q_data->h = pix->height;
- if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG)
- q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
- else
+ if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG) {
+ /*
+ * During encoding Exynos4x12 SoCs access wider memory area
+ * than it results from Image_x and Image_y values written to
+ * the JPEG_IMAGE_SIZE register. In order to avoid sysmmu
+ * page fault calculate proper buffer size in such a case.
+ */
+ if (ct->jpeg->variant->version == SJPEG_EXYNOS4 &&
+ f_type == FMT_TYPE_OUTPUT && ct->mode == S5P_JPEG_ENCODE)
+ q_data->size = exynos4_jpeg_get_output_buffer_size(ct,
+ f,
+ q_data->fmt->depth);
+ else
+ q_data->size = q_data->w * q_data->h *
+ q_data->fmt->depth >> 3;
+ } else {
q_data->size = pix->sizeimage;
+ }
if (f_type == FMT_TYPE_OUTPUT) {
ctrl_subs = v4l2_ctrl_find(&ct->ctrl_handler,
@@ -1182,8 +1235,7 @@ static int s5p_jpeg_g_selection(struct file *file, void *priv,
struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
- s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- ctx->jpeg->variant->version != SJPEG_S5P)
+ s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
/* For JPEG blob active == default == bounds */
@@ -1571,7 +1623,7 @@ static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
.job_abort = s5p_jpeg_job_abort,
}
;
-static struct v4l2_m2m_ops exynos_jpeg_m2m_ops = {
+static struct v4l2_m2m_ops exynos4_jpeg_m2m_ops = {
.device_run = exynos4_jpeg_device_run,
.job_ready = s5p_jpeg_job_ready,
.job_abort = s5p_jpeg_job_abort,
@@ -1670,13 +1722,11 @@ static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
return ret > 0 ? 0 : ret;
}
-static int s5p_jpeg_stop_streaming(struct vb2_queue *q)
+static void s5p_jpeg_stop_streaming(struct vb2_queue *q)
{
struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(q);
pm_runtime_put(ctx->jpeg->dev);
-
- return 0;
}
static struct vb2_ops s5p_jpeg_qops = {
@@ -1845,7 +1895,7 @@ static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
return IRQ_HANDLED;
}
-static void *jpeg_get_drv_data(struct platform_device *pdev);
+static void *jpeg_get_drv_data(struct device *dev);
/*
* ============================================================================
@@ -1857,18 +1907,14 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
{
struct s5p_jpeg *jpeg;
struct resource *res;
- struct v4l2_m2m_ops *samsung_jpeg_m2m_ops;
int ret;
- if (!pdev->dev.of_node)
- return -ENODEV;
-
/* JPEG IP abstraction struct */
jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
if (!jpeg)
return -ENOMEM;
- jpeg->variant = jpeg_get_drv_data(pdev);
+ jpeg->variant = jpeg_get_drv_data(&pdev->dev);
mutex_init(&jpeg->lock);
spin_lock_init(&jpeg->slock);
@@ -1911,13 +1957,8 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
goto clk_get_rollback;
}
- if (jpeg->variant->version == SJPEG_S5P)
- samsung_jpeg_m2m_ops = &s5p_jpeg_m2m_ops;
- else
- samsung_jpeg_m2m_ops = &exynos_jpeg_m2m_ops;
-
/* mem2mem device */
- jpeg->m2m_dev = v4l2_m2m_init(samsung_jpeg_m2m_ops);
+ jpeg->m2m_dev = v4l2_m2m_init(jpeg->variant->m2m_ops);
if (IS_ERR(jpeg->m2m_dev)) {
v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
ret = PTR_ERR(jpeg->m2m_dev);
@@ -2102,15 +2143,18 @@ static const struct dev_pm_ops s5p_jpeg_pm_ops = {
SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL)
};
-#ifdef CONFIG_OF
static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
.version = SJPEG_S5P,
.jpeg_irq = s5p_jpeg_irq,
+ .m2m_ops = &s5p_jpeg_m2m_ops,
+ .fmt_ver_flag = SJPEG_FMT_FLAG_S5P,
};
static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
.version = SJPEG_EXYNOS4,
.jpeg_irq = exynos4_jpeg_irq,
+ .m2m_ops = &exynos4_jpeg_m2m_ops,
+ .fmt_ver_flag = SJPEG_FMT_FLAG_EXYNOS4,
};
static const struct of_device_id samsung_jpeg_match[] = {
@@ -2129,19 +2173,21 @@ static const struct of_device_id samsung_jpeg_match[] = {
MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
-static void *jpeg_get_drv_data(struct platform_device *pdev)
+static void *jpeg_get_drv_data(struct device *dev)
{
struct s5p_jpeg_variant *driver_data = NULL;
const struct of_device_id *match;
- match = of_match_node(of_match_ptr(samsung_jpeg_match),
- pdev->dev.of_node);
+ if (!IS_ENABLED(CONFIG_OF) || !dev->of_node)
+ return &s5p_jpeg_drvdata;
+
+ match = of_match_node(samsung_jpeg_match, dev->of_node);
+
if (match)
driver_data = (struct s5p_jpeg_variant *)match->data;
return driver_data;
}
-#endif
static struct platform_driver s5p_jpeg_driver = {
.probe = s5p_jpeg_probe,
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.h b/drivers/media/platform/s5p-jpeg/jpeg-core.h
index f482dbf55d5f..3e4786329727 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.h
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.h
@@ -117,8 +117,10 @@ struct s5p_jpeg {
};
struct s5p_jpeg_variant {
- unsigned int version;
- irqreturn_t (*jpeg_irq)(int irq, void *priv);
+ unsigned int version;
+ unsigned int fmt_ver_flag;
+ struct v4l2_m2m_ops *m2m_ops;
+ irqreturn_t (*jpeg_irq)(int irq, void *priv);
};
/**
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h
index 8d0b686d9adb..51cb2dd0e13a 100644
--- a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h
+++ b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h
@@ -141,6 +141,7 @@
#define S5P_FIMV_D_SLICE_IF_ENABLE_V6 0xf4c4
#define S5P_FIMV_D_PICTURE_TAG_V6 0xf4c8
#define S5P_FIMV_D_STREAM_DATA_SIZE_V6 0xf4d0
+#define S5P_FIMV_D_INIT_BUFFER_OPTIONS_V6 0xf47c
/* Display information register */
#define S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V6 0xf500
@@ -381,8 +382,7 @@
(DIV_ROUND_UP((mbw) * (mbh), 32) * 16))
#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V6(w, h) (((w) * 192) + 64)
#define S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6(w, h) \
- ((w) * ((h) * 64 + 144) + (2048/16 * (h) * 64) + \
- (2048/16 * 256 + 8320))
+ ((w) * 144 + 8192 * (h) + 49216 + 1048576)
#define S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6(w, h) \
(2096 * ((w) + (h) + 1))
#define S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6(w, h) ((w) * 400)
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v7.h b/drivers/media/platform/s5p-mfc/regs-mfc-v7.h
index ea5ec2a711af..1a5c6fdf7846 100644
--- a/drivers/media/platform/s5p-mfc/regs-mfc-v7.h
+++ b/drivers/media/platform/s5p-mfc/regs-mfc-v7.h
@@ -18,8 +18,6 @@
#define S5P_FIMV_CODEC_VP8_ENC_V7 25
/* Additional registers for v7 */
-#define S5P_FIMV_D_INIT_BUFFER_OPTIONS_V7 0xf47c
-
#define S5P_FIMV_E_SOURCE_FIRST_ADDR_V7 0xf9e0
#define S5P_FIMV_E_SOURCE_SECOND_ADDR_V7 0xf9e4
#define S5P_FIMV_E_SOURCE_THIRD_ADDR_V7 0xf9e8
@@ -56,6 +54,7 @@
(SZ_1M + ((w) * 144) + (8192 * (h)) + 49216)
#define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V7(w, h) \
- (((w) * 48) + (((w) + 1) / 2 * 128) + 144 + 8192)
+ (((w) * 48) + 8192 + ((((w) + 1) / 2) * 128) + 144 + \
+ ((((((w) * 16) * ((h) * 16)) * 3) / 2) * 4))
#endif /*_REGS_MFC_V7_H*/
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h
new file mode 100644
index 000000000000..cc7cbec51b5e
--- /dev/null
+++ b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h
@@ -0,0 +1,124 @@
+/*
+ * Register definition file for Samsung MFC V8.x Interface (FIMV) driver
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.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.
+ */
+
+#ifndef _REGS_MFC_V8_H
+#define _REGS_MFC_V8_H
+
+#include <linux/sizes.h>
+#include "regs-mfc-v7.h"
+
+/* Additional registers for v8 */
+#define S5P_FIMV_D_MVC_NUM_VIEWS_V8 0xf104
+#define S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8 0xf144
+#define S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8 0xf148
+#define S5P_FIMV_D_MV_BUFFER_SIZE_V8 0xf150
+
+#define S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8 0xf138
+#define S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8 0xf13c
+
+#define S5P_FIMV_D_FIRST_PLANE_DPB_V8 0xf160
+#define S5P_FIMV_D_SECOND_PLANE_DPB_V8 0xf260
+#define S5P_FIMV_D_MV_BUFFER_V8 0xf460
+
+#define S5P_FIMV_D_NUM_MV_V8 0xf134
+#define S5P_FIMV_D_INIT_BUFFER_OPTIONS_V8 0xf154
+
+#define S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V8 0xf560
+#define S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V8 0xf564
+
+#define S5P_FIMV_D_CPB_BUFFER_ADDR_V8 0xf5b0
+#define S5P_FIMV_D_CPB_BUFFER_SIZE_V8 0xf5b4
+#define S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V8 0xf5bc
+#define S5P_FIMV_D_CPB_BUFFER_OFFSET_V8 0xf5c0
+#define S5P_FIMV_D_SLICE_IF_ENABLE_V8 0xf5c4
+#define S5P_FIMV_D_STREAM_DATA_SIZE_V8 0xf5d0
+
+/* Display information register */
+#define S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V8 0xf600
+#define S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V8 0xf604
+
+/* Display status */
+#define S5P_FIMV_D_DISPLAY_STATUS_V8 0xf608
+
+#define S5P_FIMV_D_DISPLAY_FIRST_PLANE_ADDR_V8 0xf60c
+#define S5P_FIMV_D_DISPLAY_SECOND_PLANE_ADDR_V8 0xf610
+
+#define S5P_FIMV_D_DISPLAY_FRAME_TYPE_V8 0xf618
+#define S5P_FIMV_D_DISPLAY_CROP_INFO1_V8 0xf61c
+#define S5P_FIMV_D_DISPLAY_CROP_INFO2_V8 0xf620
+#define S5P_FIMV_D_DISPLAY_PICTURE_PROFILE_V8 0xf624
+
+/* Decoded picture information register */
+#define S5P_FIMV_D_DECODED_STATUS_V8 0xf644
+#define S5P_FIMV_D_DECODED_FIRST_PLANE_ADDR_V8 0xf648
+#define S5P_FIMV_D_DECODED_SECOND_PLANE_ADDR_V8 0xf64c
+#define S5P_FIMV_D_DECODED_THIRD_PLANE_ADDR_V8 0xf650
+#define S5P_FIMV_D_DECODED_FRAME_TYPE_V8 0xf654
+#define S5P_FIMV_D_DECODED_NAL_SIZE_V8 0xf664
+
+/* Returned value register for specific setting */
+#define S5P_FIMV_D_RET_PICTURE_TAG_TOP_V8 0xf674
+#define S5P_FIMV_D_RET_PICTURE_TAG_BOT_V8 0xf678
+#define S5P_FIMV_D_MVC_VIEW_ID_V8 0xf6d8
+
+/* SEI related information */
+#define S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V8 0xf6dc
+
+/* Encoder Registers */
+#define S5P_FIMV_E_FIXED_PICTURE_QP_V8 0xf794
+#define S5P_FIMV_E_RC_CONFIG_V8 0xf798
+#define S5P_FIMV_E_RC_QP_BOUND_V8 0xf79c
+#define S5P_FIMV_E_RC_RPARAM_V8 0xf7a4
+#define S5P_FIMV_E_MB_RC_CONFIG_V8 0xf7a8
+#define S5P_FIMV_E_PADDING_CTRL_V8 0xf7ac
+#define S5P_FIMV_E_MV_HOR_RANGE_V8 0xf7b4
+#define S5P_FIMV_E_MV_VER_RANGE_V8 0xf7b8
+
+#define S5P_FIMV_E_VBV_BUFFER_SIZE_V8 0xf78c
+#define S5P_FIMV_E_VBV_INIT_DELAY_V8 0xf790
+
+#define S5P_FIMV_E_ASPECT_RATIO_V8 0xfb4c
+#define S5P_FIMV_E_EXTENDED_SAR_V8 0xfb50
+#define S5P_FIMV_E_H264_OPTIONS_V8 0xfb54
+
+/* MFCv8 Context buffer sizes */
+#define MFC_CTX_BUF_SIZE_V8 (30 * SZ_1K) /* 30KB */
+#define MFC_H264_DEC_CTX_BUF_SIZE_V8 (2 * SZ_1M) /* 2MB */
+#define MFC_OTHER_DEC_CTX_BUF_SIZE_V8 (20 * SZ_1K) /* 20KB */
+#define MFC_H264_ENC_CTX_BUF_SIZE_V8 (100 * SZ_1K) /* 100KB */
+#define MFC_OTHER_ENC_CTX_BUF_SIZE_V8 (10 * SZ_1K) /* 10KB */
+
+/* Buffer size defines */
+#define S5P_FIMV_TMV_BUFFER_SIZE_V8(w, h) (((w) + 1) * ((h) + 1) * 8)
+
+#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V8(w, h) (((w) * 704) + 2176)
+#define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V8(w, h) \
+ (((w) * 576 + (h) * 128) + 4128)
+
+#define S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V8(w, h) \
+ (((w) * 592) + 2336)
+#define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V8(w, h) \
+ (((w) * 576) + 10512 + \
+ ((((((w) * 16) * ((h) * 16)) * 3) / 2) * 4))
+#define S5P_FIMV_ME_BUFFER_SIZE_V8(imw, imh, mbw, mbh) \
+ ((DIV_ROUND_UP((mbw * 16), 64) * DIV_ROUND_UP((mbh * 16), 64) * 256) \
+ + (DIV_ROUND_UP((mbw) * (mbh), 32) * 16))
+
+/* BUffer alignment defines */
+#define S5P_FIMV_D_ALIGN_PLANE_SIZE_V8 64
+
+/* MFCv8 variant defines */
+#define MAX_FW_SIZE_V8 (SZ_1M) /* 1MB */
+#define MAX_CPB_SIZE_V8 (3 * SZ_1M) /* 3MB */
+#define MFC_VERSION_V8 0x80
+#define MFC_NUM_PORTS_V8 1
+
+#endif /*_REGS_MFC_V8_H*/
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index 89356ae90238..41723180d10c 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -309,12 +309,15 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
{
struct s5p_mfc_dev *dev = ctx->dev;
unsigned int dst_frame_status;
+ unsigned int dec_frame_status;
struct s5p_mfc_buf *src_buf;
unsigned long flags;
unsigned int res_change;
dst_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev)
& S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK;
+ dec_frame_status = s5p_mfc_hw_call(dev->mfc_ops, get_dec_status, dev)
+ & S5P_FIMV_DEC_STATUS_DECODING_STATUS_MASK;
res_change = (s5p_mfc_hw_call(dev->mfc_ops, get_dspl_status, dev)
& S5P_FIMV_DEC_STATUS_RESOLUTION_MASK)
>> S5P_FIMV_DEC_STATUS_RESOLUTION_SHIFT;
@@ -339,16 +342,23 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
/* All frames remaining in the buffer have been extracted */
if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_EMPTY) {
if (ctx->state == MFCINST_RES_CHANGE_FLUSH) {
+ static const struct v4l2_event ev_src_ch = {
+ .type = V4L2_EVENT_SOURCE_CHANGE,
+ .u.src_change.changes =
+ V4L2_EVENT_SRC_CH_RESOLUTION,
+ };
+
s5p_mfc_handle_frame_all_extracted(ctx);
ctx->state = MFCINST_RES_CHANGE_END;
+ v4l2_event_queue_fh(&ctx->fh, &ev_src_ch);
+
goto leave_handle_frame;
} else {
s5p_mfc_handle_frame_all_extracted(ctx);
}
}
- if (dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY ||
- dst_frame_status == S5P_FIMV_DEC_STATUS_DECODING_ONLY)
+ if (dec_frame_status == S5P_FIMV_DEC_STATUS_DECODING_DISPLAY)
s5p_mfc_handle_frame_copy_time(ctx);
/* A frame has been decoded and is in the buffer */
@@ -366,6 +376,7 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
ctx->consumed_stream += s5p_mfc_hw_call(dev->mfc_ops,
get_consumed_stream, dev);
if (ctx->codec_mode != S5P_MFC_CODEC_H264_DEC &&
+ ctx->codec_mode != S5P_MFC_CODEC_VP8_DEC &&
ctx->consumed_stream + STUFF_BYTE <
src_buf->b->v4l2_planes[0].bytesused) {
/* Run MFC again on the same buffer */
@@ -641,6 +652,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
case S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET:
clear_work_bit(ctx);
+ ctx->inst_no = MFC_NO_INSTANCE_SET;
ctx->state = MFCINST_FREE;
wake_up(&ctx->queue);
goto irq_cleanup_hw;
@@ -761,7 +773,7 @@ static int s5p_mfc_open(struct file *file)
goto err_bad_node;
}
ctx->fh.ctrl_handler = &ctx->ctrl_handler;
- ctx->inst_no = -1;
+ ctx->inst_no = MFC_NO_INSTANCE_SET;
/* Load firmware if this is the first instance */
if (dev->num_inst == 1) {
dev->watchdog_timer.expires = jiffies +
@@ -871,29 +883,11 @@ static int s5p_mfc_release(struct file *file)
vb2_queue_release(&ctx->vq_dst);
/* Mark context as idle */
clear_work_bit_irqsave(ctx);
- /* If instance was initialised then
+ /* If instance was initialised and not yet freed,
* return instance and free resources */
- if (ctx->inst_no != MFC_NO_INSTANCE_SET) {
+ if (ctx->state != MFCINST_FREE && ctx->state != MFCINST_INIT) {
mfc_debug(2, "Has to free instance\n");
- ctx->state = MFCINST_RETURN_INST;
- set_work_bit_irqsave(ctx);
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
- /* Wait until instance is returned or timeout occurred */
- if (s5p_mfc_wait_for_done_ctx
- (ctx, S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0)) {
- s5p_mfc_clock_off();
- mfc_err("Err returning instance\n");
- }
- mfc_debug(2, "After free instance\n");
- /* Free resources */
- s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
- s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
- if (ctx->type == MFCINST_DECODER)
- s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer,
- ctx);
-
- ctx->inst_no = MFC_NO_INSTANCE_SET;
+ s5p_mfc_close_mfc_inst(dev, ctx);
}
/* hardware locking scheme */
if (dev->curr_ctx == ctx->num)
@@ -1207,6 +1201,7 @@ static int s5p_mfc_probe(struct platform_device *pdev)
/* Initialize HW ops and commands based on MFC version */
s5p_mfc_init_hw_ops(dev);
s5p_mfc_init_hw_cmds(dev);
+ s5p_mfc_init_regs(dev);
pr_debug("%s--\n", __func__);
return 0;
@@ -1352,6 +1347,7 @@ struct s5p_mfc_buf_align mfc_buf_align_v5 = {
static struct s5p_mfc_variant mfc_drvdata_v5 = {
.version = MFC_VERSION,
+ .version_bit = MFC_V5_BIT,
.port_num = MFC_NUM_PORTS,
.buf_size = &buf_size_v5,
.buf_align = &mfc_buf_align_v5,
@@ -1378,6 +1374,7 @@ struct s5p_mfc_buf_align mfc_buf_align_v6 = {
static struct s5p_mfc_variant mfc_drvdata_v6 = {
.version = MFC_VERSION_V6,
+ .version_bit = MFC_V6_BIT,
.port_num = MFC_NUM_PORTS_V6,
.buf_size = &buf_size_v6,
.buf_align = &mfc_buf_align_v6,
@@ -1404,12 +1401,40 @@ struct s5p_mfc_buf_align mfc_buf_align_v7 = {
static struct s5p_mfc_variant mfc_drvdata_v7 = {
.version = MFC_VERSION_V7,
+ .version_bit = MFC_V7_BIT,
.port_num = MFC_NUM_PORTS_V7,
.buf_size = &buf_size_v7,
.buf_align = &mfc_buf_align_v7,
.fw_name = "s5p-mfc-v7.fw",
};
+struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = {
+ .dev_ctx = MFC_CTX_BUF_SIZE_V8,
+ .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V8,
+ .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V8,
+ .h264_enc_ctx = MFC_H264_ENC_CTX_BUF_SIZE_V8,
+ .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V8,
+};
+
+struct s5p_mfc_buf_size buf_size_v8 = {
+ .fw = MAX_FW_SIZE_V8,
+ .cpb = MAX_CPB_SIZE_V8,
+ .priv = &mfc_buf_size_v8,
+};
+
+struct s5p_mfc_buf_align mfc_buf_align_v8 = {
+ .base = 0,
+};
+
+static struct s5p_mfc_variant mfc_drvdata_v8 = {
+ .version = MFC_VERSION_V8,
+ .version_bit = MFC_V8_BIT,
+ .port_num = MFC_NUM_PORTS_V8,
+ .buf_size = &buf_size_v8,
+ .buf_align = &mfc_buf_align_v8,
+ .fw_name = "s5p-mfc-v8.fw",
+};
+
static struct platform_device_id mfc_driver_ids[] = {
{
.name = "s5p-mfc",
@@ -1423,6 +1448,9 @@ static struct platform_device_id mfc_driver_ids[] = {
}, {
.name = "s5p-mfc-v7",
.driver_data = (unsigned long)&mfc_drvdata_v7,
+ }, {
+ .name = "s5p-mfc-v8",
+ .driver_data = (unsigned long)&mfc_drvdata_v8,
},
{},
};
@@ -1438,6 +1466,9 @@ static const struct of_device_id exynos_mfc_match[] = {
}, {
.compatible = "samsung,mfc-v7",
.data = &mfc_drvdata_v7,
+ }, {
+ .compatible = "samsung,mfc-v8",
+ .data = &mfc_drvdata_v8,
},
{},
};
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
index 5c28cc3e699b..b04360cd34f0 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
@@ -23,8 +23,7 @@
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-core.h>
#include "regs-mfc.h"
-#include "regs-mfc-v6.h"
-#include "regs-mfc-v7.h"
+#include "regs-mfc-v8.h"
/* Definitions related to MFC memory */
@@ -223,6 +222,7 @@ struct s5p_mfc_buf_align {
struct s5p_mfc_variant {
unsigned int version;
unsigned int port_num;
+ u32 version_bit;
struct s5p_mfc_buf_size *buf_size;
struct s5p_mfc_buf_align *buf_align;
char *fw_name;
@@ -330,6 +330,7 @@ struct s5p_mfc_dev {
int warn_start;
struct s5p_mfc_hw_ops *mfc_ops;
struct s5p_mfc_hw_cmds *mfc_cmds;
+ const struct s5p_mfc_regs *mfc_regs;
};
/**
@@ -663,6 +664,7 @@ struct s5p_mfc_fmt {
u32 codec_mode;
enum s5p_mfc_fmt_type type;
u32 num_planes;
+ u32 versions;
};
/**
@@ -700,6 +702,13 @@ void set_work_bit_irqsave(struct s5p_mfc_ctx *ctx);
(dev->variant->port_num ? 1 : 0) : 0) : 0)
#define IS_TWOPORT(dev) (dev->variant->port_num == 2 ? 1 : 0)
#define IS_MFCV6_PLUS(dev) (dev->variant->version >= 0x60 ? 1 : 0)
-#define IS_MFCV7(dev) (dev->variant->version >= 0x70 ? 1 : 0)
+#define IS_MFCV7_PLUS(dev) (dev->variant->version >= 0x70 ? 1 : 0)
+#define IS_MFCV8(dev) (dev->variant->version >= 0x80 ? 1 : 0)
+
+#define MFC_V5_BIT BIT(0)
+#define MFC_V6_BIT BIT(1)
+#define MFC_V7_BIT BIT(2)
+#define MFC_V8_BIT BIT(3)
+
#endif /* S5P_MFC_COMMON_H_ */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
index ee05f2dd439b..6c3f8f743900 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
@@ -400,3 +400,65 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
return 0;
}
+int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
+{
+ int ret = 0;
+
+ ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_instance_buffer, ctx);
+ if (ret) {
+ mfc_err("Failed allocating instance buffer\n");
+ goto err;
+ }
+
+ if (ctx->type == MFCINST_DECODER) {
+ ret = s5p_mfc_hw_call(dev->mfc_ops,
+ alloc_dec_temp_buffers, ctx);
+ if (ret) {
+ mfc_err("Failed allocating temporary buffers\n");
+ goto err_free_inst_buf;
+ }
+ }
+
+ set_work_bit_irqsave(ctx);
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+ if (s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) {
+ /* Error or timeout */
+ mfc_err("Error getting instance from hardware\n");
+ ret = -EIO;
+ goto err_free_desc_buf;
+ }
+
+ mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
+ return ret;
+
+err_free_desc_buf:
+ if (ctx->type == MFCINST_DECODER)
+ s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
+err_free_inst_buf:
+ s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
+err:
+ return ret;
+}
+
+void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
+{
+ ctx->state = MFCINST_RETURN_INST;
+ set_work_bit_irqsave(ctx);
+ s5p_mfc_clean_ctx_int_flags(ctx);
+ s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
+ /* Wait until instance is returned or timeout occurred */
+ if (s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0))
+ mfc_err("Err returning instance\n");
+
+ /* Free resources */
+ s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
+ s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
+ if (ctx->type == MFCINST_DECODER)
+ s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
+
+ ctx->inst_no = MFC_NO_INSTANCE_SET;
+ ctx->state = MFCINST_FREE;
+}
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h
index 6a9b6f8606bb..8e5df041edf7 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.h
@@ -28,4 +28,7 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev);
int s5p_mfc_reset(struct s5p_mfc_dev *dev);
+int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx);
+void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx);
+
#endif /* S5P_MFC_CTRL_H */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index 8faf9691712d..4d93835dec9d 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -25,15 +25,13 @@
#include <media/v4l2-event.h>
#include <media/videobuf2-core.h>
#include "s5p_mfc_common.h"
+#include "s5p_mfc_ctrl.h"
#include "s5p_mfc_debug.h"
#include "s5p_mfc_dec.h"
#include "s5p_mfc_intr.h"
#include "s5p_mfc_opr.h"
#include "s5p_mfc_pm.h"
-#define DEF_SRC_FMT_DEC V4L2_PIX_FMT_H264
-#define DEF_DST_FMT_DEC V4L2_PIX_FMT_NV12MT_16X16
-
static struct s5p_mfc_fmt formats[] = {
{
.name = "4:2:0 2 Planes 16x16 Tiles",
@@ -41,6 +39,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
+ .versions = MFC_V6_BIT | MFC_V7_BIT,
},
{
.name = "4:2:0 2 Planes 64x32 Tiles",
@@ -48,6 +47,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
+ .versions = MFC_V5_BIT,
},
{
.name = "4:2:0 2 Planes Y/CbCr",
@@ -55,6 +55,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
+ .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT,
},
{
.name = "4:2:0 2 Planes Y/CrCb",
@@ -62,6 +63,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
+ .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT,
},
{
.name = "H264 Encoded Stream",
@@ -69,6 +71,8 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_H264_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
+ .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
+ MFC_V8_BIT,
},
{
.name = "H264/MVC Encoded Stream",
@@ -76,6 +80,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_H264_MVC_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
+ .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT,
},
{
.name = "H263 Encoded Stream",
@@ -83,6 +88,8 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_H263_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
+ .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
+ MFC_V8_BIT,
},
{
.name = "MPEG1 Encoded Stream",
@@ -90,6 +97,8 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_MPEG2_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
+ .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
+ MFC_V8_BIT,
},
{
.name = "MPEG2 Encoded Stream",
@@ -97,6 +106,8 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_MPEG2_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
+ .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
+ MFC_V8_BIT,
},
{
.name = "MPEG4 Encoded Stream",
@@ -104,6 +115,8 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_MPEG4_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
+ .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
+ MFC_V8_BIT,
},
{
.name = "XviD Encoded Stream",
@@ -111,6 +124,8 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_MPEG4_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
+ .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
+ MFC_V8_BIT,
},
{
.name = "VC1 Encoded Stream",
@@ -118,6 +133,8 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_VC1_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
+ .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
+ MFC_V8_BIT,
},
{
.name = "VC1 RCV Encoded Stream",
@@ -125,6 +142,8 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_VC1RCV_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
+ .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
+ MFC_V8_BIT,
},
{
.name = "VP8 Encoded Stream",
@@ -132,6 +151,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_VP8_DEC,
.type = MFC_FMT_DEC,
.num_planes = 1,
+ .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT,
},
};
@@ -262,8 +282,10 @@ static int vidioc_querycap(struct file *file, void *priv,
}
/* Enumerate format */
-static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
+static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
+ bool mplane, bool out)
{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
struct s5p_mfc_fmt *fmt;
int i, j = 0;
@@ -276,6 +298,8 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
continue;
else if (!out && formats[i].type != MFC_FMT_RAW)
continue;
+ else if ((dev->variant->version_bit & formats[i].versions) == 0)
+ continue;
if (j == f->index)
break;
@@ -292,25 +316,25 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
struct v4l2_fmtdesc *f)
{
- return vidioc_enum_fmt(f, false, false);
+ return vidioc_enum_fmt(file, f, false, false);
}
static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
struct v4l2_fmtdesc *f)
{
- return vidioc_enum_fmt(f, true, false);
+ return vidioc_enum_fmt(file, f, true, false);
}
-static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
+static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- return vidioc_enum_fmt(f, false, true);
+ return vidioc_enum_fmt(file, f, false, true);
}
-static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
+static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- return vidioc_enum_fmt(f, true, true);
+ return vidioc_enum_fmt(file, f, true, true);
}
/* Get format */
@@ -386,11 +410,9 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
mfc_err("Unknown codec\n");
return -EINVAL;
}
- if (!IS_MFCV6_PLUS(dev)) {
- if (fmt->fourcc == V4L2_PIX_FMT_VP8) {
- mfc_err("Not supported format.\n");
- return -EINVAL;
- }
+ if ((dev->variant->version_bit & fmt->versions) == 0) {
+ mfc_err("Unsupported format by this MFC version.\n");
+ return -EINVAL;
}
} else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
fmt = find_format(f, MFC_FMT_RAW);
@@ -398,13 +420,8 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
mfc_err("Unsupported format for destination.\n");
return -EINVAL;
}
- if (IS_MFCV6_PLUS(dev) &&
- (fmt->fourcc == V4L2_PIX_FMT_NV12MT)) {
- mfc_err("Not supported format.\n");
- return -EINVAL;
- } else if (!IS_MFCV6_PLUS(dev) &&
- (fmt->fourcc != V4L2_PIX_FMT_NV12MT)) {
- mfc_err("Not supported format.\n");
+ if ((dev->variant->version_bit & fmt->versions) == 0) {
+ mfc_err("Unsupported format by this MFC version.\n");
return -EINVAL;
}
}
@@ -462,104 +479,131 @@ out:
return ret;
}
-/* Reqeust buffers */
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *reqbufs)
+static int reqbufs_output(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
+ struct v4l2_requestbuffers *reqbufs)
{
- struct s5p_mfc_dev *dev = video_drvdata(file);
- struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
int ret = 0;
- if (reqbufs->memory != V4L2_MEMORY_MMAP) {
- mfc_err("Only V4L2_MEMORY_MAP is supported\n");
- return -EINVAL;
- }
- if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
- /* Can only request buffers after an instance has been opened.*/
- if (ctx->state == MFCINST_INIT) {
- ctx->src_bufs_cnt = 0;
- if (reqbufs->count == 0) {
- mfc_debug(2, "Freeing buffers\n");
- s5p_mfc_clock_on();
- ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
- s5p_mfc_clock_off();
- return ret;
- }
- /* Decoding */
- if (ctx->output_state != QUEUE_FREE) {
- mfc_err("Bufs have already been requested\n");
- return -EINVAL;
- }
- s5p_mfc_clock_on();
- ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
- s5p_mfc_clock_off();
- if (ret) {
- mfc_err("vb2_reqbufs on output failed\n");
- return ret;
- }
- mfc_debug(2, "vb2_reqbufs: %d\n", ret);
- ctx->output_state = QUEUE_BUFS_REQUESTED;
- }
- } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- ctx->dst_bufs_cnt = 0;
- if (reqbufs->count == 0) {
- mfc_debug(2, "Freeing buffers\n");
- s5p_mfc_clock_on();
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
- s5p_mfc_clock_off();
- return ret;
+ s5p_mfc_clock_on();
+
+ if (reqbufs->count == 0) {
+ mfc_debug(2, "Freeing buffers\n");
+ ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+ if (ret)
+ goto out;
+ s5p_mfc_close_mfc_inst(dev, ctx);
+ ctx->src_bufs_cnt = 0;
+ ctx->output_state = QUEUE_FREE;
+ } else if (ctx->output_state == QUEUE_FREE) {
+ /* Can only request buffers when we have a valid format set. */
+ WARN_ON(ctx->src_bufs_cnt != 0);
+ if (ctx->state != MFCINST_INIT) {
+ mfc_err("Reqbufs called in an invalid state\n");
+ ret = -EINVAL;
+ goto out;
}
- if (ctx->capture_state != QUEUE_FREE) {
- mfc_err("Bufs have already been requested\n");
- return -EINVAL;
- }
- ctx->capture_state = QUEUE_BUFS_REQUESTED;
- s5p_mfc_clock_on();
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
- s5p_mfc_clock_off();
+
+ mfc_debug(2, "Allocating %d buffers for OUTPUT queue\n",
+ reqbufs->count);
+ ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+ if (ret)
+ goto out;
+
+ ret = s5p_mfc_open_mfc_inst(dev, ctx);
if (ret) {
- mfc_err("vb2_reqbufs on capture failed\n");
- return ret;
- }
- if (reqbufs->count < ctx->pb_count) {
- mfc_err("Not enough buffers allocated\n");
reqbufs->count = 0;
- s5p_mfc_clock_on();
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
- s5p_mfc_clock_off();
- return -ENOMEM;
+ vb2_reqbufs(&ctx->vq_src, reqbufs);
+ goto out;
}
+
+ ctx->output_state = QUEUE_BUFS_REQUESTED;
+ } else {
+ mfc_err("Buffers have already been requested\n");
+ ret = -EINVAL;
+ }
+out:
+ s5p_mfc_clock_off();
+ if (ret)
+ mfc_err("Failed allocating buffers for OUTPUT queue\n");
+ return ret;
+}
+
+static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ int ret = 0;
+
+ s5p_mfc_clock_on();
+
+ if (reqbufs->count == 0) {
+ mfc_debug(2, "Freeing buffers\n");
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ if (ret)
+ goto out;
+ s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
+ ctx->dst_bufs_cnt = 0;
+ } else if (ctx->capture_state == QUEUE_FREE) {
+ WARN_ON(ctx->dst_bufs_cnt != 0);
+ mfc_debug(2, "Allocating %d buffers for CAPTURE queue\n",
+ reqbufs->count);
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ if (ret)
+ goto out;
+
+ ctx->capture_state = QUEUE_BUFS_REQUESTED;
ctx->total_dpb_count = reqbufs->count;
+
ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_codec_buffers, ctx);
if (ret) {
mfc_err("Failed to allocate decoding buffers\n");
reqbufs->count = 0;
- s5p_mfc_clock_on();
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
- s5p_mfc_clock_off();
- return -ENOMEM;
- }
- if (ctx->dst_bufs_cnt == ctx->total_dpb_count) {
- ctx->capture_state = QUEUE_BUFS_MMAPED;
- } else {
- mfc_err("Not all buffers passed to buf_init\n");
- reqbufs->count = 0;
- s5p_mfc_clock_on();
- ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
- s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers,
- ctx);
- s5p_mfc_clock_off();
- return -ENOMEM;
+ vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ ret = -ENOMEM;
+ ctx->capture_state = QUEUE_FREE;
+ goto out;
}
+
+ WARN_ON(ctx->dst_bufs_cnt != ctx->total_dpb_count);
+ ctx->capture_state = QUEUE_BUFS_MMAPED;
+
if (s5p_mfc_ctx_ready(ctx))
set_work_bit_irqsave(ctx);
s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
- s5p_mfc_wait_for_done_ctx(ctx,
- S5P_MFC_R2H_CMD_INIT_BUFFERS_RET, 0);
+ s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_INIT_BUFFERS_RET,
+ 0);
+ } else {
+ mfc_err("Buffers have already been requested\n");
+ ret = -EINVAL;
}
+out:
+ s5p_mfc_clock_off();
+ if (ret)
+ mfc_err("Failed allocating buffers for CAPTURE queue\n");
return ret;
}
+/* Reqeust buffers */
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
+ struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
+
+ if (reqbufs->memory != V4L2_MEMORY_MMAP) {
+ mfc_err("Only V4L2_MEMORY_MAP is supported\n");
+ return -EINVAL;
+ }
+
+ if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ return reqbufs_output(dev, ctx, reqbufs);
+ } else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ return reqbufs_capture(dev, ctx, reqbufs);
+ } else {
+ mfc_err("Invalid type requested\n");
+ return -EINVAL;
+ }
+}
+
/* Query buffer */
static int vidioc_querybuf(struct file *file, void *priv,
struct v4l2_buffer *buf)
@@ -573,7 +617,7 @@ static int vidioc_querybuf(struct file *file, void *priv,
return -EINVAL;
}
mfc_debug(2, "State: %d, buf->type: %d\n", ctx->state, buf->type);
- if (ctx->state == MFCINST_INIT &&
+ if (ctx->state == MFCINST_GOT_INST &&
buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
ret = vb2_querybuf(&ctx->vq_src, buf);
} else if (ctx->state == MFCINST_RUNNING &&
@@ -649,39 +693,11 @@ static int vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
struct s5p_mfc_ctx *ctx = fh_to_ctx(priv);
- struct s5p_mfc_dev *dev = ctx->dev;
int ret = -EINVAL;
mfc_debug_enter();
- if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
-
- if (ctx->state == MFCINST_INIT) {
- ctx->dst_bufs_cnt = 0;
- ctx->src_bufs_cnt = 0;
- ctx->capture_state = QUEUE_FREE;
- ctx->output_state = QUEUE_FREE;
- s5p_mfc_hw_call(dev->mfc_ops, alloc_instance_buffer,
- ctx);
- s5p_mfc_hw_call(dev->mfc_ops, alloc_dec_temp_buffers,
- ctx);
- set_work_bit_irqsave(ctx);
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
-
- if (s5p_mfc_wait_for_done_ctx(ctx,
- S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) {
- /* Error or timeout */
- mfc_err("Error getting instance from hardware\n");
- s5p_mfc_hw_call(dev->mfc_ops,
- release_instance_buffer, ctx);
- s5p_mfc_hw_call(dev->mfc_ops,
- release_dec_desc_buffer, ctx);
- return -EIO;
- }
- mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
- }
+ if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
ret = vb2_streamon(&ctx->vq_src, type);
- }
else if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
ret = vb2_streamon(&ctx->vq_dst, type);
mfc_debug_leave();
@@ -851,6 +867,8 @@ static int vidioc_subscribe_event(struct v4l2_fh *fh,
switch (sub->type) {
case V4L2_EVENT_EOS:
return v4l2_event_subscribe(fh, sub, 2, NULL);
+ case V4L2_EVENT_SOURCE_CHANGE:
+ return v4l2_src_change_event_subscribe(fh, sub);
default:
return -EINVAL;
}
@@ -1027,7 +1045,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
return 0;
}
-static int s5p_mfc_stop_streaming(struct vb2_queue *q)
+static void s5p_mfc_stop_streaming(struct vb2_queue *q)
{
unsigned long flags;
struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
@@ -1071,7 +1089,6 @@ static int s5p_mfc_stop_streaming(struct vb2_queue *q)
}
if (aborted)
ctx->state = MFCINST_RUNNING;
- return 0;
}
@@ -1191,9 +1208,14 @@ void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx)
void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx)
{
struct v4l2_format f;
- f.fmt.pix_mp.pixelformat = DEF_SRC_FMT_DEC;
+ f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_H264;
ctx->src_fmt = find_format(&f, MFC_FMT_DEC);
- f.fmt.pix_mp.pixelformat = DEF_DST_FMT_DEC;
+ if (IS_MFCV8(ctx->dev))
+ f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12M;
+ else if (IS_MFCV6_PLUS(ctx->dev))
+ f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT_16X16;
+ else
+ f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12MT;
ctx->dst_fmt = find_format(&f, MFC_FMT_RAW);
mfc_debug(2, "Default src_fmt is %x, dest_fmt is %x\n",
(unsigned int)ctx->src_fmt, (unsigned int)ctx->dst_fmt);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
index df83cd157bab..d26b2484ca10 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -26,6 +26,7 @@
#include <media/v4l2-ctrls.h>
#include <media/videobuf2-core.h>
#include "s5p_mfc_common.h"
+#include "s5p_mfc_ctrl.h"
#include "s5p_mfc_debug.h"
#include "s5p_mfc_enc.h"
#include "s5p_mfc_intr.h"
@@ -41,6 +42,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
+ .versions = MFC_V6_BIT | MFC_V7_BIT,
},
{
.name = "4:2:0 2 Planes 64x32 Tiles",
@@ -48,6 +50,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
+ .versions = MFC_V5_BIT,
},
{
.name = "4:2:0 2 Planes Y/CbCr",
@@ -55,6 +58,8 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
+ .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
+ MFC_V8_BIT,
},
{
.name = "4:2:0 2 Planes Y/CrCb",
@@ -62,6 +67,8 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
+ .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
+ MFC_V8_BIT,
},
{
.name = "H264 Encoded Stream",
@@ -69,6 +76,8 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_H264_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
+ .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
+ MFC_V8_BIT,
},
{
.name = "MPEG4 Encoded Stream",
@@ -76,6 +85,8 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_MPEG4_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
+ .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
+ MFC_V8_BIT,
},
{
.name = "H263 Encoded Stream",
@@ -83,6 +94,8 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_H263_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
+ .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
+ MFC_V8_BIT,
},
{
.name = "VP8 Encoded Stream",
@@ -90,6 +103,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_VP8_ENC,
.type = MFC_FMT_ENC,
.num_planes = 1,
+ .versions = MFC_V7_BIT | MFC_V8_BIT,
},
};
@@ -772,13 +786,16 @@ static int enc_post_seq_start(struct s5p_mfc_ctx *ctx)
if (p->seq_hdr_mode == V4L2_MPEG_VIDEO_HEADER_MODE_SEPARATE) {
spin_lock_irqsave(&dev->irqlock, flags);
- dst_mb = list_entry(ctx->dst_queue.next,
- struct s5p_mfc_buf, list);
- list_del(&dst_mb->list);
- ctx->dst_queue_cnt--;
- vb2_set_plane_payload(dst_mb->b, 0,
- s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size, dev));
- vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE);
+ if (!list_empty(&ctx->dst_queue)) {
+ dst_mb = list_entry(ctx->dst_queue.next,
+ struct s5p_mfc_buf, list);
+ list_del(&dst_mb->list);
+ ctx->dst_queue_cnt--;
+ vb2_set_plane_payload(dst_mb->b, 0,
+ s5p_mfc_hw_call(dev->mfc_ops, get_enc_strm_size,
+ dev));
+ vb2_buffer_done(dst_mb->b, VB2_BUF_STATE_DONE);
+ }
spin_unlock_irqrestore(&dev->irqlock, flags);
}
@@ -883,8 +900,7 @@ static int enc_post_frame_start(struct s5p_mfc_ctx *ctx)
mfc_debug(2, "enc src count: %d, enc ref count: %d\n",
ctx->src_queue_cnt, ctx->ref_queue_cnt);
}
- if (strm_size > 0) {
- /* at least one more dest. buffers exist always */
+ if ((ctx->dst_queue_cnt > 0) && (strm_size > 0)) {
mb_entry = list_entry(ctx->dst_queue.next, struct s5p_mfc_buf,
list);
list_del(&mb_entry->list);
@@ -937,8 +953,10 @@ static int vidioc_querycap(struct file *file, void *priv,
return 0;
}
-static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
+static int vidioc_enum_fmt(struct file *file, struct v4l2_fmtdesc *f,
+ bool mplane, bool out)
{
+ struct s5p_mfc_dev *dev = video_drvdata(file);
struct s5p_mfc_fmt *fmt;
int i, j = 0;
@@ -951,6 +969,9 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
continue;
else if (!out && formats[i].type != MFC_FMT_ENC)
continue;
+ else if ((dev->variant->version_bit & formats[i].versions) == 0)
+ continue;
+
if (j == f->index) {
fmt = &formats[i];
strlcpy(f->description, fmt->name,
@@ -966,25 +987,25 @@ static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool mplane, bool out)
static int vidioc_enum_fmt_vid_cap(struct file *file, void *pirv,
struct v4l2_fmtdesc *f)
{
- return vidioc_enum_fmt(f, false, false);
+ return vidioc_enum_fmt(file, f, false, false);
}
static int vidioc_enum_fmt_vid_cap_mplane(struct file *file, void *pirv,
struct v4l2_fmtdesc *f)
{
- return vidioc_enum_fmt(f, true, false);
+ return vidioc_enum_fmt(file, f, true, false);
}
static int vidioc_enum_fmt_vid_out(struct file *file, void *prov,
struct v4l2_fmtdesc *f)
{
- return vidioc_enum_fmt(f, false, true);
+ return vidioc_enum_fmt(file, f, false, true);
}
static int vidioc_enum_fmt_vid_out_mplane(struct file *file, void *prov,
struct v4l2_fmtdesc *f)
{
- return vidioc_enum_fmt(f, true, true);
+ return vidioc_enum_fmt(file, f, true, true);
}
static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
@@ -1035,16 +1056,14 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
mfc_err("failed to try output format\n");
return -EINVAL;
}
-
- if (!IS_MFCV7(dev) && (fmt->fourcc == V4L2_PIX_FMT_VP8)) {
- mfc_err("VP8 is supported only in MFC v7\n");
- return -EINVAL;
- }
-
if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) {
mfc_err("must be set encoding output size\n");
return -EINVAL;
}
+ if ((dev->variant->version_bit & fmt->versions) == 0) {
+ mfc_err("Unsupported format by this MFC version.\n");
+ return -EINVAL;
+ }
pix_fmt_mp->plane_fmt[0].bytesperline =
pix_fmt_mp->plane_fmt[0].sizeimage;
@@ -1055,22 +1074,15 @@ static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
return -EINVAL;
}
- if (!IS_MFCV6_PLUS(dev)) {
- if (fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) {
- mfc_err("Not supported format.\n");
- return -EINVAL;
- }
- } else if (IS_MFCV6_PLUS(dev)) {
- if (fmt->fourcc == V4L2_PIX_FMT_NV12MT) {
- mfc_err("Not supported format.\n");
- return -EINVAL;
- }
- }
-
if (fmt->num_planes != pix_fmt_mp->num_planes) {
mfc_err("failed to try output format\n");
return -EINVAL;
}
+ if ((dev->variant->version_bit & fmt->versions) == 0) {
+ mfc_err("Unsupported format by this MFC version.\n");
+ return -EINVAL;
+ }
+
v4l_bound_align_image(&pix_fmt_mp->width, 8, 1920, 1,
&pix_fmt_mp->height, 4, 1080, 1, 0);
} else {
@@ -1104,20 +1116,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
pix_fmt_mp->plane_fmt[0].bytesperline = 0;
ctx->dst_bufs_cnt = 0;
ctx->capture_state = QUEUE_FREE;
- s5p_mfc_hw_call(dev->mfc_ops, alloc_instance_buffer, ctx);
- set_work_bit_irqsave(ctx);
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
- if (s5p_mfc_wait_for_done_ctx(ctx, \
- S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 1)) {
- /* Error or timeout */
- mfc_err("Error getting instance from hardware\n");
- s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer,
- ctx);
- ret = -EIO;
- goto out;
- }
- mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
+ ret = s5p_mfc_open_mfc_inst(dev, ctx);
} else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
/* src_fmt is validated by call to vidioc_try_fmt */
ctx->src_fmt = find_format(f, MFC_FMT_RAW);
@@ -1138,7 +1137,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
ctx->output_state = QUEUE_FREE;
} else {
mfc_err("invalid buf type\n");
- return -EINVAL;
+ ret = -EINVAL;
}
out:
mfc_debug_leave();
@@ -1954,7 +1953,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
return 0;
}
-static int s5p_mfc_stop_streaming(struct vb2_queue *q)
+static void s5p_mfc_stop_streaming(struct vb2_queue *q)
{
unsigned long flags;
struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
@@ -1983,7 +1982,6 @@ static int s5p_mfc_stop_streaming(struct vb2_queue *q)
ctx->src_queue_cnt = 0;
}
spin_unlock_irqrestore(&dev->irqlock, flags);
- return 0;
}
static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
index 3c01c339d696..c9a227428e6a 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c
@@ -31,6 +31,12 @@ void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev)
dev->mfc_ops = s5p_mfc_ops;
}
+void s5p_mfc_init_regs(struct s5p_mfc_dev *dev)
+{
+ if (IS_MFCV6_PLUS(dev))
+ dev->mfc_regs = s5p_mfc_init_regs_v6_plus(dev);
+}
+
int s5p_mfc_alloc_priv_buf(struct device *dev,
struct s5p_mfc_priv_buf *b)
{
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
index 754c540e7a7e..7a7ad32ee608 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.h
@@ -17,6 +17,259 @@
#include "s5p_mfc_common.h"
+struct s5p_mfc_regs {
+
+ /* codec common registers */
+ void *risc_on;
+ void *risc2host_int;
+ void *host2risc_int;
+ void *risc_base_address;
+ void *mfc_reset;
+ void *host2risc_command;
+ void *risc2host_command;
+ void *mfc_bus_reset_ctrl;
+ void *firmware_version;
+ void *instance_id;
+ void *codec_type;
+ void *context_mem_addr;
+ void *context_mem_size;
+ void *pixel_format;
+ void *metadata_enable;
+ void *mfc_version;
+ void *dbg_info_enable;
+ void *dbg_buffer_addr;
+ void *dbg_buffer_size;
+ void *hed_control;
+ void *mfc_timeout_value;
+ void *hed_shared_mem_addr;
+ void *dis_shared_mem_addr;/* only v7 */
+ void *ret_instance_id;
+ void *error_code;
+ void *dbg_buffer_output_size;
+ void *metadata_status;
+ void *metadata_addr_mb_info;
+ void *metadata_size_mb_info;
+ void *dbg_info_stage_counter;
+
+ /* decoder registers */
+ void *d_crc_ctrl;
+ void *d_dec_options;
+ void *d_display_delay;
+ void *d_set_frame_width;
+ void *d_set_frame_height;
+ void *d_sei_enable;
+ void *d_min_num_dpb;
+ void *d_min_first_plane_dpb_size;
+ void *d_min_second_plane_dpb_size;
+ void *d_min_third_plane_dpb_size;/* only v8 */
+ void *d_min_num_mv;
+ void *d_mvc_num_views;
+ void *d_min_num_dis;/* only v7 */
+ void *d_min_first_dis_size;/* only v7 */
+ void *d_min_second_dis_size;/* only v7 */
+ void *d_min_third_dis_size;/* only v7 */
+ void *d_post_filter_luma_dpb0;/* v7 and v8 */
+ void *d_post_filter_luma_dpb1;/* v7 and v8 */
+ void *d_post_filter_luma_dpb2;/* only v7 */
+ void *d_post_filter_chroma_dpb0;/* v7 and v8 */
+ void *d_post_filter_chroma_dpb1;/* v7 and v8 */
+ void *d_post_filter_chroma_dpb2;/* only v7 */
+ void *d_num_dpb;
+ void *d_num_mv;
+ void *d_init_buffer_options;
+ void *d_first_plane_dpb_stride_size;/* only v8 */
+ void *d_second_plane_dpb_stride_size;/* only v8 */
+ void *d_third_plane_dpb_stride_size;/* only v8 */
+ void *d_first_plane_dpb_size;
+ void *d_second_plane_dpb_size;
+ void *d_third_plane_dpb_size;/* only v8 */
+ void *d_mv_buffer_size;
+ void *d_first_plane_dpb;
+ void *d_second_plane_dpb;
+ void *d_third_plane_dpb;
+ void *d_mv_buffer;
+ void *d_scratch_buffer_addr;
+ void *d_scratch_buffer_size;
+ void *d_metadata_buffer_addr;
+ void *d_metadata_buffer_size;
+ void *d_nal_start_options;/* v7 and v8 */
+ void *d_cpb_buffer_addr;
+ void *d_cpb_buffer_size;
+ void *d_available_dpb_flag_upper;
+ void *d_available_dpb_flag_lower;
+ void *d_cpb_buffer_offset;
+ void *d_slice_if_enable;
+ void *d_picture_tag;
+ void *d_stream_data_size;
+ void *d_dynamic_dpb_flag_upper;/* v7 and v8 */
+ void *d_dynamic_dpb_flag_lower;/* v7 and v8 */
+ void *d_display_frame_width;
+ void *d_display_frame_height;
+ void *d_display_status;
+ void *d_display_first_plane_addr;
+ void *d_display_second_plane_addr;
+ void *d_display_third_plane_addr;/* only v8 */
+ void *d_display_frame_type;
+ void *d_display_crop_info1;
+ void *d_display_crop_info2;
+ void *d_display_picture_profile;
+ void *d_display_luma_crc;/* v7 and v8 */
+ void *d_display_chroma0_crc;/* v7 and v8 */
+ void *d_display_chroma1_crc;/* only v8 */
+ void *d_display_luma_crc_top;/* only v6 */
+ void *d_display_chroma_crc_top;/* only v6 */
+ void *d_display_luma_crc_bot;/* only v6 */
+ void *d_display_chroma_crc_bot;/* only v6 */
+ void *d_display_aspect_ratio;
+ void *d_display_extended_ar;
+ void *d_decoded_frame_width;
+ void *d_decoded_frame_height;
+ void *d_decoded_status;
+ void *d_decoded_first_plane_addr;
+ void *d_decoded_second_plane_addr;
+ void *d_decoded_third_plane_addr;/* only v8 */
+ void *d_decoded_frame_type;
+ void *d_decoded_crop_info1;
+ void *d_decoded_crop_info2;
+ void *d_decoded_picture_profile;
+ void *d_decoded_nal_size;
+ void *d_decoded_luma_crc;
+ void *d_decoded_chroma0_crc;
+ void *d_decoded_chroma1_crc;/* only v8 */
+ void *d_ret_picture_tag_top;
+ void *d_ret_picture_tag_bot;
+ void *d_ret_picture_time_top;
+ void *d_ret_picture_time_bot;
+ void *d_chroma_format;
+ void *d_vc1_info;/* v7 and v8 */
+ void *d_mpeg4_info;
+ void *d_h264_info;
+ void *d_metadata_addr_concealed_mb;
+ void *d_metadata_size_concealed_mb;
+ void *d_metadata_addr_vc1_param;
+ void *d_metadata_size_vc1_param;
+ void *d_metadata_addr_sei_nal;
+ void *d_metadata_size_sei_nal;
+ void *d_metadata_addr_vui;
+ void *d_metadata_size_vui;
+ void *d_metadata_addr_mvcvui;/* v7 and v8 */
+ void *d_metadata_size_mvcvui;/* v7 and v8 */
+ void *d_mvc_view_id;
+ void *d_frame_pack_sei_avail;
+ void *d_frame_pack_arrgment_id;
+ void *d_frame_pack_sei_info;
+ void *d_frame_pack_grid_pos;
+ void *d_display_recovery_sei_info;/* v7 and v8 */
+ void *d_decoded_recovery_sei_info;/* v7 and v8 */
+ void *d_display_first_addr;/* only v7 */
+ void *d_display_second_addr;/* only v7 */
+ void *d_display_third_addr;/* only v7 */
+ void *d_decoded_first_addr;/* only v7 */
+ void *d_decoded_second_addr;/* only v7 */
+ void *d_decoded_third_addr;/* only v7 */
+ void *d_used_dpb_flag_upper;/* v7 and v8 */
+ void *d_used_dpb_flag_lower;/* v7 and v8 */
+
+ /* encoder registers */
+ void *e_frame_width;
+ void *e_frame_height;
+ void *e_cropped_frame_width;
+ void *e_cropped_frame_height;
+ void *e_frame_crop_offset;
+ void *e_enc_options;
+ void *e_picture_profile;
+ void *e_vbv_buffer_size;
+ void *e_vbv_init_delay;
+ void *e_fixed_picture_qp;
+ void *e_rc_config;
+ void *e_rc_qp_bound;
+ void *e_rc_qp_bound_pb;/* v7 and v8 */
+ void *e_rc_mode;
+ void *e_mb_rc_config;
+ void *e_padding_ctrl;
+ void *e_air_threshold;
+ void *e_mv_hor_range;
+ void *e_mv_ver_range;
+ void *e_num_dpb;
+ void *e_luma_dpb;
+ void *e_chroma_dpb;
+ void *e_me_buffer;
+ void *e_scratch_buffer_addr;
+ void *e_scratch_buffer_size;
+ void *e_tmv_buffer0;
+ void *e_tmv_buffer1;
+ void *e_ir_buffer_addr;/* v7 and v8 */
+ void *e_source_first_plane_addr;
+ void *e_source_second_plane_addr;
+ void *e_source_third_plane_addr;/* v7 and v8 */
+ void *e_source_first_plane_stride;/* v7 and v8 */
+ void *e_source_second_plane_stride;/* v7 and v8 */
+ void *e_source_third_plane_stride;/* v7 and v8 */
+ void *e_stream_buffer_addr;
+ void *e_stream_buffer_size;
+ void *e_roi_buffer_addr;
+ void *e_param_change;
+ void *e_ir_size;
+ void *e_gop_config;
+ void *e_mslice_mode;
+ void *e_mslice_size_mb;
+ void *e_mslice_size_bits;
+ void *e_frame_insertion;
+ void *e_rc_frame_rate;
+ void *e_rc_bit_rate;
+ void *e_rc_roi_ctrl;
+ void *e_picture_tag;
+ void *e_bit_count_enable;
+ void *e_max_bit_count;
+ void *e_min_bit_count;
+ void *e_metadata_buffer_addr;
+ void *e_metadata_buffer_size;
+ void *e_encoded_source_first_plane_addr;
+ void *e_encoded_source_second_plane_addr;
+ void *e_encoded_source_third_plane_addr;/* v7 and v8 */
+ void *e_stream_size;
+ void *e_slice_type;
+ void *e_picture_count;
+ void *e_ret_picture_tag;
+ void *e_stream_buffer_write_pointer; /* only v6 */
+ void *e_recon_luma_dpb_addr;
+ void *e_recon_chroma_dpb_addr;
+ void *e_metadata_addr_enc_slice;
+ void *e_metadata_size_enc_slice;
+ void *e_mpeg4_options;
+ void *e_mpeg4_hec_period;
+ void *e_aspect_ratio;
+ void *e_extended_sar;
+ void *e_h264_options;
+ void *e_h264_options_2;/* v7 and v8 */
+ void *e_h264_lf_alpha_offset;
+ void *e_h264_lf_beta_offset;
+ void *e_h264_i_period;
+ void *e_h264_fmo_slice_grp_map_type;
+ void *e_h264_fmo_num_slice_grp_minus1;
+ void *e_h264_fmo_slice_grp_change_dir;
+ void *e_h264_fmo_slice_grp_change_rate_minus1;
+ void *e_h264_fmo_run_length_minus1_0;
+ void *e_h264_aso_slice_order_0;
+ void *e_h264_chroma_qp_offset;
+ void *e_h264_num_t_layer;
+ void *e_h264_hierarchical_qp_layer0;
+ void *e_h264_frame_packing_sei_info;
+ void *e_h264_nal_control;/* v7 and v8 */
+ void *e_mvc_frame_qp_view1;
+ void *e_mvc_rc_bit_rate_view1;
+ void *e_mvc_rc_qbound_view1;
+ void *e_mvc_rc_mode_view1;
+ void *e_mvc_inter_view_prediction_on;
+ void *e_vp8_options;/* v7 and v8 */
+ void *e_vp8_filter_options;/* v7 and v8 */
+ void *e_vp8_golden_frame_option;/* v7 and v8 */
+ void *e_vp8_num_t_layer;/* v7 and v8 */
+ void *e_vp8_hierarchical_qp_layer0;/* v7 and v8 */
+ void *e_vp8_hierarchical_qp_layer1;/* v7 and v8 */
+ void *e_vp8_hierarchical_qp_layer2;/* v7 and v8 */
+};
+
struct s5p_mfc_hw_ops {
int (*alloc_dec_temp_buffers)(struct s5p_mfc_ctx *ctx);
void (*release_dec_desc_buffer)(struct s5p_mfc_ctx *ctx);
@@ -80,6 +333,7 @@ struct s5p_mfc_hw_ops {
};
void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev);
+void s5p_mfc_init_regs(struct s5p_mfc_dev *dev);
int s5p_mfc_alloc_priv_buf(struct device *dev,
struct s5p_mfc_priv_buf *b);
void s5p_mfc_release_priv_buf(struct device *dev,
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
index f64621ae9b5a..4f5e0ead90c6 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -43,10 +43,10 @@
} while (0)
#endif /* S5P_MFC_DEBUG_REGWRITE */
-#define READL(offset) readl(dev->regs_base + (offset))
-#define WRITEL(data, offset) writel((data), dev->regs_base + (offset))
-#define OFFSETA(x) (((x) - dev->port_a) >> S5P_FIMV_MEM_OFFSET)
-#define OFFSETB(x) (((x) - dev->port_b) >> S5P_FIMV_MEM_OFFSET)
+#define READL(reg) \
+ (WARN_ON_ONCE(!(reg)) ? 0 : readl(reg))
+#define WRITEL(data, reg) \
+ (WARN_ON_ONCE(!(reg)) ? 0 : writel((data), (reg)))
/* Allocate temporary buffers for decoding */
static int s5p_mfc_alloc_dec_temp_buffers_v6(struct s5p_mfc_ctx *ctx)
@@ -77,7 +77,12 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
ctx->luma_size, ctx->chroma_size, ctx->mv_size);
mfc_debug(2, "Totals bufs: %d\n", ctx->total_dpb_count);
} else if (ctx->type == MFCINST_ENCODER) {
- ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 *
+ if (IS_MFCV8(dev))
+ ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 *
+ ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V8(mb_width, mb_height),
+ S5P_FIMV_TMV_BUFFER_ALIGN_V6);
+ else
+ ctx->tmv_buffer_size = S5P_FIMV_NUM_TMV_BUFFERS_V6 *
ALIGN(S5P_FIMV_TMV_BUFFER_SIZE_V6(mb_width, mb_height),
S5P_FIMV_TMV_BUFFER_ALIGN_V6);
@@ -87,10 +92,16 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
ctx->chroma_dpb_size = ALIGN((mb_width * mb_height) *
S5P_FIMV_CHROMA_MB_TO_PIXEL_V6,
S5P_FIMV_CHROMA_DPB_BUFFER_ALIGN_V6);
- ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V6(
- ctx->img_width, ctx->img_height,
- mb_width, mb_height),
- S5P_FIMV_ME_BUFFER_ALIGN_V6);
+ if (IS_MFCV8(dev))
+ ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V8(
+ ctx->img_width, ctx->img_height,
+ mb_width, mb_height),
+ S5P_FIMV_ME_BUFFER_ALIGN_V6);
+ else
+ ctx->me_buffer_size = ALIGN(S5P_FIMV_ME_BUFFER_SIZE_V6(
+ ctx->img_width, ctx->img_height,
+ mb_width, mb_height),
+ S5P_FIMV_ME_BUFFER_ALIGN_V6);
mfc_debug(2, "recon luma size: %d chroma size: %d\n",
ctx->luma_dpb_size, ctx->chroma_dpb_size);
@@ -102,8 +113,14 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
switch (ctx->codec_mode) {
case S5P_MFC_CODEC_H264_DEC:
case S5P_MFC_CODEC_H264_MVC_DEC:
- ctx->scratch_buf_size =
- S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V6(
+ if (IS_MFCV8(dev))
+ ctx->scratch_buf_size =
+ S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V8(
+ mb_width,
+ mb_height);
+ else
+ ctx->scratch_buf_size =
+ S5P_FIMV_SCRATCH_BUF_SIZE_H264_DEC_V6(
mb_width,
mb_height);
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
@@ -113,7 +130,7 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
(ctx->mv_count * ctx->mv_size);
break;
case S5P_MFC_CODEC_MPEG4_DEC:
- if (IS_MFCV7(dev)) {
+ if (IS_MFCV7_PLUS(dev)) {
ctx->scratch_buf_size =
S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V7(
mb_width,
@@ -153,19 +170,31 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
ctx->bank1.size = ctx->scratch_buf_size;
break;
case S5P_MFC_CODEC_VP8_DEC:
- ctx->scratch_buf_size =
- S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V6(
- mb_width,
- mb_height);
+ if (IS_MFCV8(dev))
+ ctx->scratch_buf_size =
+ S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V8(
+ mb_width,
+ mb_height);
+ else
+ ctx->scratch_buf_size =
+ S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V6(
+ mb_width,
+ mb_height);
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
ctx->bank1.size = ctx->scratch_buf_size;
break;
case S5P_MFC_CODEC_H264_ENC:
- ctx->scratch_buf_size =
- S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V6(
+ if (IS_MFCV8(dev))
+ ctx->scratch_buf_size =
+ S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V8(
mb_width,
mb_height);
+ else
+ ctx->scratch_buf_size =
+ S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V6(
+ mb_width,
+ mb_height);
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
ctx->bank1.size =
@@ -189,10 +218,16 @@ static int s5p_mfc_alloc_codec_buffers_v6(struct s5p_mfc_ctx *ctx)
ctx->bank2.size = 0;
break;
case S5P_MFC_CODEC_VP8_ENC:
- ctx->scratch_buf_size =
- S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V7(
+ if (IS_MFCV8(dev))
+ ctx->scratch_buf_size =
+ S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V8(
mb_width,
mb_height);
+ else
+ ctx->scratch_buf_size =
+ S5P_FIMV_SCRATCH_BUF_SIZE_VP8_ENC_V7(
+ mb_width,
+ mb_height);
ctx->scratch_buf_size = ALIGN(ctx->scratch_buf_size,
S5P_FIMV_SCRATCH_BUFFER_ALIGN_V6);
ctx->bank1.size =
@@ -332,6 +367,12 @@ static void s5p_mfc_dec_calc_dpb_size_v6(struct s5p_mfc_ctx *ctx)
ctx->luma_size = calc_plane(ctx->img_width, ctx->img_height);
ctx->chroma_size = calc_plane(ctx->img_width, (ctx->img_height >> 1));
+ if (IS_MFCV8(ctx->dev)) {
+ /* MFCv8 needs additional 64 bytes for luma,chroma dpb*/
+ ctx->luma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
+ ctx->chroma_size += S5P_FIMV_D_ALIGN_PLANE_SIZE_V8;
+ }
+
if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) {
ctx->mv_size = S5P_MFC_DEC_MV_SIZE_V6(ctx->img_width,
@@ -354,7 +395,7 @@ static void s5p_mfc_enc_calc_src_size_v6(struct s5p_mfc_ctx *ctx)
ctx->chroma_size = ALIGN((mb_width * mb_height) * 128, 256);
/* MFCv7 needs pad bytes for Luma and Chroma */
- if (IS_MFCV7(ctx->dev)) {
+ if (IS_MFCV7_PLUS(ctx->dev)) {
ctx->luma_size += MFC_LUMA_PAD_BYTES_V7;
ctx->chroma_size += MFC_CHROMA_PAD_BYTES_V7;
}
@@ -366,16 +407,17 @@ static int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx,
unsigned int strm_size)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size;
mfc_debug_enter();
mfc_debug(2, "inst_no: %d, buf_addr: 0x%08x,\n"
"buf_size: 0x%08x (%d)\n",
ctx->inst_no, buf_addr, strm_size, strm_size);
- WRITEL(strm_size, S5P_FIMV_D_STREAM_DATA_SIZE_V6);
- WRITEL(buf_addr, S5P_FIMV_D_CPB_BUFFER_ADDR_V6);
- WRITEL(buf_size->cpb, S5P_FIMV_D_CPB_BUFFER_SIZE_V6);
- WRITEL(start_num_byte, S5P_FIMV_D_CPB_BUFFER_OFFSET_V6);
+ WRITEL(strm_size, mfc_regs->d_stream_data_size);
+ WRITEL(buf_addr, mfc_regs->d_cpb_buffer_addr);
+ WRITEL(buf_size->cpb, mfc_regs->d_cpb_buffer_size);
+ WRITEL(start_num_byte, mfc_regs->d_cpb_buffer_offset);
mfc_debug_leave();
return 0;
@@ -387,6 +429,7 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
unsigned int frame_size, i;
unsigned int frame_size_ch, frame_size_mv;
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
size_t buf_addr1;
int buf_size1;
int align_gap;
@@ -398,19 +441,27 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
mfc_debug(2, "Total DPB COUNT: %d\n", ctx->total_dpb_count);
mfc_debug(2, "Setting display delay to %d\n", ctx->display_delay);
- WRITEL(ctx->total_dpb_count, S5P_FIMV_D_NUM_DPB_V6);
- WRITEL(ctx->luma_size, S5P_FIMV_D_LUMA_DPB_SIZE_V6);
- WRITEL(ctx->chroma_size, S5P_FIMV_D_CHROMA_DPB_SIZE_V6);
+ WRITEL(ctx->total_dpb_count, mfc_regs->d_num_dpb);
+ WRITEL(ctx->luma_size, mfc_regs->d_first_plane_dpb_size);
+ WRITEL(ctx->chroma_size, mfc_regs->d_second_plane_dpb_size);
+
+ WRITEL(buf_addr1, mfc_regs->d_scratch_buffer_addr);
+ WRITEL(ctx->scratch_buf_size, mfc_regs->d_scratch_buffer_size);
+
+ if (IS_MFCV8(dev)) {
+ WRITEL(ctx->img_width,
+ mfc_regs->d_first_plane_dpb_stride_size);
+ WRITEL(ctx->img_width,
+ mfc_regs->d_second_plane_dpb_stride_size);
+ }
- WRITEL(buf_addr1, S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V6);
- WRITEL(ctx->scratch_buf_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V6);
buf_addr1 += ctx->scratch_buf_size;
buf_size1 -= ctx->scratch_buf_size;
if (ctx->codec_mode == S5P_FIMV_CODEC_H264_DEC ||
ctx->codec_mode == S5P_FIMV_CODEC_H264_MVC_DEC){
- WRITEL(ctx->mv_size, S5P_FIMV_D_MV_BUFFER_SIZE_V6);
- WRITEL(ctx->mv_count, S5P_FIMV_D_NUM_MV_V6);
+ WRITEL(ctx->mv_size, mfc_regs->d_mv_buffer_size);
+ WRITEL(ctx->mv_count, mfc_regs->d_num_mv);
}
frame_size = ctx->luma_size;
@@ -424,11 +475,11 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
mfc_debug(2, "Luma %d: %x\n", i,
ctx->dst_bufs[i].cookie.raw.luma);
WRITEL(ctx->dst_bufs[i].cookie.raw.luma,
- S5P_FIMV_D_LUMA_DPB_V6 + i * 4);
+ mfc_regs->d_first_plane_dpb + i * 4);
mfc_debug(2, "\tChroma %d: %x\n", i,
ctx->dst_bufs[i].cookie.raw.chroma);
WRITEL(ctx->dst_bufs[i].cookie.raw.chroma,
- S5P_FIMV_D_CHROMA_DPB_V6 + i * 4);
+ mfc_regs->d_second_plane_dpb + i * 4);
}
if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC ||
ctx->codec_mode == S5P_MFC_CODEC_H264_MVC_DEC) {
@@ -441,7 +492,7 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
mfc_debug(2, "\tBuf1: %x, size: %d\n",
buf_addr1, buf_size1);
- WRITEL(buf_addr1, S5P_FIMV_D_MV_BUFFER_V6 + i * 4);
+ WRITEL(buf_addr1, mfc_regs->d_mv_buffer + i * 4);
buf_addr1 += frame_size_mv;
buf_size1 -= frame_size_mv;
}
@@ -454,7 +505,7 @@ static int s5p_mfc_set_dec_frame_buffer_v6(struct s5p_mfc_ctx *ctx)
return -ENOMEM;
}
- WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6);
+ WRITEL(ctx->inst_no, mfc_regs->instance_id);
s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
S5P_FIMV_CH_INIT_BUFS_V6, NULL);
@@ -467,9 +518,10 @@ static int s5p_mfc_set_enc_stream_buffer_v6(struct s5p_mfc_ctx *ctx,
unsigned long addr, unsigned int size)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
- WRITEL(addr, S5P_FIMV_E_STREAM_BUFFER_ADDR_V6); /* 16B align */
- WRITEL(size, S5P_FIMV_E_STREAM_BUFFER_SIZE_V6);
+ WRITEL(addr, mfc_regs->e_stream_buffer_addr); /* 16B align */
+ WRITEL(size, mfc_regs->e_stream_buffer_size);
mfc_debug(2, "stream buf addr: 0x%08lx, size: 0x%d\n",
addr, size);
@@ -481,14 +533,10 @@ static void s5p_mfc_set_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
unsigned long y_addr, unsigned long c_addr)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
- if (IS_MFCV7(dev)) {
- WRITEL(y_addr, S5P_FIMV_E_SOURCE_FIRST_ADDR_V7);
- WRITEL(c_addr, S5P_FIMV_E_SOURCE_SECOND_ADDR_V7);
- } else {
- WRITEL(y_addr, S5P_FIMV_E_SOURCE_LUMA_ADDR_V6);
- WRITEL(c_addr, S5P_FIMV_E_SOURCE_CHROMA_ADDR_V6);
- }
+ WRITEL(y_addr, mfc_regs->e_source_first_plane_addr);
+ WRITEL(c_addr, mfc_regs->e_source_second_plane_addr);
mfc_debug(2, "enc src y buf addr: 0x%08lx\n", y_addr);
mfc_debug(2, "enc src c buf addr: 0x%08lx\n", c_addr);
@@ -498,18 +546,14 @@ static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
unsigned long *y_addr, unsigned long *c_addr)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
unsigned long enc_recon_y_addr, enc_recon_c_addr;
- if (IS_MFCV7(dev)) {
- *y_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7);
- *c_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7);
- } else {
- *y_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR_V6);
- *c_addr = READL(S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR_V6);
- }
+ *y_addr = READL(mfc_regs->e_encoded_source_first_plane_addr);
+ *c_addr = READL(mfc_regs->e_encoded_source_second_plane_addr);
- enc_recon_y_addr = READL(S5P_FIMV_E_RECON_LUMA_DPB_ADDR_V6);
- enc_recon_c_addr = READL(S5P_FIMV_E_RECON_CHROMA_DPB_ADDR_V6);
+ enc_recon_y_addr = READL(mfc_regs->e_recon_luma_dpb_addr);
+ enc_recon_c_addr = READL(mfc_regs->e_recon_chroma_dpb_addr);
mfc_debug(2, "recon y addr: 0x%08lx\n", enc_recon_y_addr);
mfc_debug(2, "recon c addr: 0x%08lx\n", enc_recon_c_addr);
@@ -519,6 +563,7 @@ static void s5p_mfc_get_enc_frame_buffer_v6(struct s5p_mfc_ctx *ctx,
static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
size_t buf_addr1;
int i, buf_size1;
@@ -530,24 +575,24 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx)
mfc_debug(2, "Buf1: %p (%d)\n", (void *)buf_addr1, buf_size1);
for (i = 0; i < ctx->pb_count; i++) {
- WRITEL(buf_addr1, S5P_FIMV_E_LUMA_DPB_V6 + (4 * i));
+ WRITEL(buf_addr1, mfc_regs->e_luma_dpb + (4 * i));
buf_addr1 += ctx->luma_dpb_size;
- WRITEL(buf_addr1, S5P_FIMV_E_CHROMA_DPB_V6 + (4 * i));
+ WRITEL(buf_addr1, mfc_regs->e_chroma_dpb + (4 * i));
buf_addr1 += ctx->chroma_dpb_size;
- WRITEL(buf_addr1, S5P_FIMV_E_ME_BUFFER_V6 + (4 * i));
+ WRITEL(buf_addr1, mfc_regs->e_me_buffer + (4 * i));
buf_addr1 += ctx->me_buffer_size;
buf_size1 -= (ctx->luma_dpb_size + ctx->chroma_dpb_size +
ctx->me_buffer_size);
}
- WRITEL(buf_addr1, S5P_FIMV_E_SCRATCH_BUFFER_ADDR_V6);
- WRITEL(ctx->scratch_buf_size, S5P_FIMV_E_SCRATCH_BUFFER_SIZE_V6);
+ WRITEL(buf_addr1, mfc_regs->e_scratch_buffer_addr);
+ WRITEL(ctx->scratch_buf_size, mfc_regs->e_scratch_buffer_size);
buf_addr1 += ctx->scratch_buf_size;
buf_size1 -= ctx->scratch_buf_size;
- WRITEL(buf_addr1, S5P_FIMV_E_TMV_BUFFER0_V6);
+ WRITEL(buf_addr1, mfc_regs->e_tmv_buffer0);
buf_addr1 += ctx->tmv_buffer_size >> 1;
- WRITEL(buf_addr1, S5P_FIMV_E_TMV_BUFFER1_V6);
+ WRITEL(buf_addr1, mfc_regs->e_tmv_buffer1);
buf_addr1 += ctx->tmv_buffer_size >> 1;
buf_size1 -= ctx->tmv_buffer_size;
@@ -558,7 +603,7 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx)
return -ENOMEM;
}
- WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6);
+ WRITEL(ctx->inst_no, mfc_regs->instance_id);
s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
S5P_FIMV_CH_INIT_BUFS_V6, NULL);
@@ -570,18 +615,19 @@ static int s5p_mfc_set_enc_ref_buffer_v6(struct s5p_mfc_ctx *ctx)
static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
/* multi-slice control */
/* multi-slice MB number or bit size */
- WRITEL(ctx->slice_mode, S5P_FIMV_E_MSLICE_MODE_V6);
+ WRITEL(ctx->slice_mode, mfc_regs->e_mslice_mode);
if (ctx->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
- WRITEL(ctx->slice_size.mb, S5P_FIMV_E_MSLICE_SIZE_MB_V6);
+ WRITEL(ctx->slice_size.mb, mfc_regs->e_mslice_size_mb);
} else if (ctx->slice_mode ==
V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
- WRITEL(ctx->slice_size.bits, S5P_FIMV_E_MSLICE_SIZE_BITS_V6);
+ WRITEL(ctx->slice_size.bits, mfc_regs->e_mslice_size_bits);
} else {
- WRITEL(0x0, S5P_FIMV_E_MSLICE_SIZE_MB_V6);
- WRITEL(0x0, S5P_FIMV_E_MSLICE_SIZE_BITS_V6);
+ WRITEL(0x0, mfc_regs->e_mslice_size_mb);
+ WRITEL(0x0, mfc_regs->e_mslice_size_bits);
}
return 0;
@@ -590,27 +636,28 @@ static int s5p_mfc_set_slice_mode(struct s5p_mfc_ctx *ctx)
static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
struct s5p_mfc_enc_params *p = &ctx->enc_params;
unsigned int reg = 0;
mfc_debug_enter();
/* width */
- WRITEL(ctx->img_width, S5P_FIMV_E_FRAME_WIDTH_V6); /* 16 align */
+ WRITEL(ctx->img_width, mfc_regs->e_frame_width); /* 16 align */
/* height */
- WRITEL(ctx->img_height, S5P_FIMV_E_FRAME_HEIGHT_V6); /* 16 align */
+ WRITEL(ctx->img_height, mfc_regs->e_frame_height); /* 16 align */
/* cropped width */
- WRITEL(ctx->img_width, S5P_FIMV_E_CROPPED_FRAME_WIDTH_V6);
+ WRITEL(ctx->img_width, mfc_regs->e_cropped_frame_width);
/* cropped height */
- WRITEL(ctx->img_height, S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6);
+ WRITEL(ctx->img_height, mfc_regs->e_cropped_frame_height);
/* cropped offset */
- WRITEL(0x0, S5P_FIMV_E_FRAME_CROP_OFFSET_V6);
+ WRITEL(0x0, mfc_regs->e_frame_crop_offset);
/* pictype : IDR period */
reg = 0;
reg |= p->gop_size & 0xFFFF;
- WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6);
+ WRITEL(reg, mfc_regs->e_gop_config);
/* multi-slice control */
/* multi-slice MB number or bit size */
@@ -618,65 +665,65 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
reg = 0;
if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB) {
reg |= (0x1 << 3);
- WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_enc_options);
ctx->slice_size.mb = p->slice_mb;
} else if (p->slice_mode == V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES) {
reg |= (0x1 << 3);
- WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_enc_options);
ctx->slice_size.bits = p->slice_bit;
} else {
reg &= ~(0x1 << 3);
- WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_enc_options);
}
s5p_mfc_set_slice_mode(ctx);
/* cyclic intra refresh */
- WRITEL(p->intra_refresh_mb, S5P_FIMV_E_IR_SIZE_V6);
- reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6);
+ WRITEL(p->intra_refresh_mb, mfc_regs->e_ir_size);
+ reg = READL(mfc_regs->e_enc_options);
if (p->intra_refresh_mb == 0)
reg &= ~(0x1 << 4);
else
reg |= (0x1 << 4);
- WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_enc_options);
/* 'NON_REFERENCE_STORE_ENABLE' for debugging */
- reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6);
+ reg = READL(mfc_regs->e_enc_options);
reg &= ~(0x1 << 9);
- WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_enc_options);
/* memory structure cur. frame */
if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12M) {
/* 0: Linear, 1: 2D tiled*/
- reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6);
+ reg = READL(mfc_regs->e_enc_options);
reg &= ~(0x1 << 7);
- WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_enc_options);
/* 0: NV12(CbCr), 1: NV21(CrCb) */
- WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT_V6);
+ WRITEL(0x0, mfc_regs->pixel_format);
} else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV21M) {
/* 0: Linear, 1: 2D tiled*/
- reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6);
+ reg = READL(mfc_regs->e_enc_options);
reg &= ~(0x1 << 7);
- WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_enc_options);
/* 0: NV12(CbCr), 1: NV21(CrCb) */
- WRITEL(0x1, S5P_FIMV_PIXEL_FORMAT_V6);
+ WRITEL(0x1, mfc_regs->pixel_format);
} else if (ctx->src_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16) {
/* 0: Linear, 1: 2D tiled*/
- reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6);
+ reg = READL(mfc_regs->e_enc_options);
reg |= (0x1 << 7);
- WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_enc_options);
/* 0: NV12(CbCr), 1: NV21(CrCb) */
- WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT_V6);
+ WRITEL(0x0, mfc_regs->pixel_format);
}
/* memory structure recon. frame */
/* 0: Linear, 1: 2D tiled */
- reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6);
+ reg = READL(mfc_regs->e_enc_options);
reg |= (0x1 << 8);
- WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_enc_options);
/* padding control & value */
- WRITEL(0x0, S5P_FIMV_E_PADDING_CTRL_V6);
+ WRITEL(0x0, mfc_regs->e_padding_ctrl);
if (p->pad) {
reg = 0;
/** enable */
@@ -687,64 +734,64 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
reg |= ((p->pad_cb & 0xFF) << 8);
/** y value */
reg |= p->pad_luma & 0xFF;
- WRITEL(reg, S5P_FIMV_E_PADDING_CTRL_V6);
+ WRITEL(reg, mfc_regs->e_padding_ctrl);
}
/* rate control config. */
reg = 0;
/* frame-level rate control */
reg |= ((p->rc_frame & 0x1) << 9);
- WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
+ WRITEL(reg, mfc_regs->e_rc_config);
/* bit rate */
if (p->rc_frame)
WRITEL(p->rc_bitrate,
- S5P_FIMV_E_RC_BIT_RATE_V6);
+ mfc_regs->e_rc_bit_rate);
else
- WRITEL(1, S5P_FIMV_E_RC_BIT_RATE_V6);
+ WRITEL(1, mfc_regs->e_rc_bit_rate);
/* reaction coefficient */
if (p->rc_frame) {
if (p->rc_reaction_coeff < TIGHT_CBR_MAX) /* tight CBR */
- WRITEL(1, S5P_FIMV_E_RC_RPARAM_V6);
+ WRITEL(1, mfc_regs->e_rc_mode);
else /* loose CBR */
- WRITEL(2, S5P_FIMV_E_RC_RPARAM_V6);
+ WRITEL(2, mfc_regs->e_rc_mode);
}
/* seq header ctrl */
- reg = READL(S5P_FIMV_E_ENC_OPTIONS_V6);
+ reg = READL(mfc_regs->e_enc_options);
reg &= ~(0x1 << 2);
reg |= ((p->seq_hdr_mode & 0x1) << 2);
/* frame skip mode */
reg &= ~(0x3);
reg |= (p->frame_skip_mode & 0x3);
- WRITEL(reg, S5P_FIMV_E_ENC_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_enc_options);
/* 'DROP_CONTROL_ENABLE', disable */
- reg = READL(S5P_FIMV_E_RC_CONFIG_V6);
+ reg = READL(mfc_regs->e_rc_config);
reg &= ~(0x1 << 10);
- WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
+ WRITEL(reg, mfc_regs->e_rc_config);
/* setting for MV range [16, 256] */
reg = (p->mv_h_range & S5P_FIMV_E_MV_RANGE_V6_MASK);
- WRITEL(reg, S5P_FIMV_E_MV_HOR_RANGE_V6);
+ WRITEL(reg, mfc_regs->e_mv_hor_range);
reg = (p->mv_v_range & S5P_FIMV_E_MV_RANGE_V6_MASK);
- WRITEL(reg, S5P_FIMV_E_MV_VER_RANGE_V6);
+ WRITEL(reg, mfc_regs->e_mv_ver_range);
- WRITEL(0x0, S5P_FIMV_E_FRAME_INSERTION_V6);
- WRITEL(0x0, S5P_FIMV_E_ROI_BUFFER_ADDR_V6);
- WRITEL(0x0, S5P_FIMV_E_PARAM_CHANGE_V6);
- WRITEL(0x0, S5P_FIMV_E_RC_ROI_CTRL_V6);
- WRITEL(0x0, S5P_FIMV_E_PICTURE_TAG_V6);
+ WRITEL(0x0, mfc_regs->e_frame_insertion);
+ WRITEL(0x0, mfc_regs->e_roi_buffer_addr);
+ WRITEL(0x0, mfc_regs->e_param_change);
+ WRITEL(0x0, mfc_regs->e_rc_roi_ctrl);
+ WRITEL(0x0, mfc_regs->e_picture_tag);
- WRITEL(0x0, S5P_FIMV_E_BIT_COUNT_ENABLE_V6);
- WRITEL(0x0, S5P_FIMV_E_MAX_BIT_COUNT_V6);
- WRITEL(0x0, S5P_FIMV_E_MIN_BIT_COUNT_V6);
+ WRITEL(0x0, mfc_regs->e_bit_count_enable);
+ WRITEL(0x0, mfc_regs->e_max_bit_count);
+ WRITEL(0x0, mfc_regs->e_min_bit_count);
- WRITEL(0x0, S5P_FIMV_E_METADATA_BUFFER_ADDR_V6);
- WRITEL(0x0, S5P_FIMV_E_METADATA_BUFFER_SIZE_V6);
+ WRITEL(0x0, mfc_regs->e_metadata_buffer_addr);
+ WRITEL(0x0, mfc_regs->e_metadata_buffer_size);
mfc_debug_leave();
@@ -754,6 +801,7 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx)
static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
struct s5p_mfc_enc_params *p = &ctx->enc_params;
struct s5p_mfc_h264_enc_params *p_h264 = &p->codec.h264;
unsigned int reg = 0;
@@ -764,10 +812,10 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
s5p_mfc_set_enc_params(ctx);
/* pictype : number of B */
- reg = READL(S5P_FIMV_E_GOP_CONFIG_V6);
+ reg = READL(mfc_regs->e_gop_config);
reg &= ~(0x3 << 16);
reg |= ((p->num_b_frame & 0x3) << 16);
- WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6);
+ WRITEL(reg, mfc_regs->e_gop_config);
/* profile & level */
reg = 0;
@@ -775,18 +823,19 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
reg |= ((p_h264->level & 0xFF) << 8);
/** profile - 0 ~ 3 */
reg |= p_h264->profile & 0x3F;
- WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6);
+ WRITEL(reg, mfc_regs->e_picture_profile);
/* rate control config. */
- reg = READL(S5P_FIMV_E_RC_CONFIG_V6);
+ reg = READL(mfc_regs->e_rc_config);
/** macroblock level rate control */
reg &= ~(0x1 << 8);
reg |= ((p->rc_mb & 0x1) << 8);
- WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
+ WRITEL(reg, mfc_regs->e_rc_config);
+
/** frame QP */
reg &= ~(0x3F);
reg |= p_h264->rc_frame_qp & 0x3F;
- WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
+ WRITEL(reg, mfc_regs->e_rc_config);
/* max & min value of QP */
reg = 0;
@@ -794,16 +843,16 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
reg |= ((p_h264->rc_max_qp & 0x3F) << 8);
/** min QP */
reg |= p_h264->rc_min_qp & 0x3F;
- WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6);
+ WRITEL(reg, mfc_regs->e_rc_qp_bound);
/* other QPs */
- WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
+ WRITEL(0x0, mfc_regs->e_fixed_picture_qp);
if (!p->rc_frame && !p->rc_mb) {
reg = 0;
reg |= ((p_h264->rc_b_frame_qp & 0x3F) << 16);
reg |= ((p_h264->rc_p_frame_qp & 0x3F) << 8);
reg |= p_h264->rc_frame_qp & 0x3F;
- WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
+ WRITEL(reg, mfc_regs->e_fixed_picture_qp);
}
/* frame rate */
@@ -811,38 +860,38 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
reg = 0;
reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
reg |= p->rc_framerate_denom & 0xFFFF;
- WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6);
+ WRITEL(reg, mfc_regs->e_rc_frame_rate);
}
/* vbv buffer size */
if (p->frame_skip_mode ==
V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
WRITEL(p_h264->cpb_size & 0xFFFF,
- S5P_FIMV_E_VBV_BUFFER_SIZE_V6);
+ mfc_regs->e_vbv_buffer_size);
if (p->rc_frame)
- WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6);
+ WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay);
}
/* interlace */
reg = 0;
reg |= ((p_h264->interlace & 0x1) << 3);
- WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_h264_options);
/* height */
if (p_h264->interlace) {
WRITEL(ctx->img_height >> 1,
- S5P_FIMV_E_FRAME_HEIGHT_V6); /* 32 align */
+ mfc_regs->e_frame_height); /* 32 align */
/* cropped height */
WRITEL(ctx->img_height >> 1,
- S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6);
+ mfc_regs->e_cropped_frame_height);
}
/* loop filter ctrl */
- reg = READL(S5P_FIMV_E_H264_OPTIONS_V6);
+ reg = READL(mfc_regs->e_h264_options);
reg &= ~(0x3 << 1);
reg |= ((p_h264->loop_filter_mode & 0x3) << 1);
- WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_h264_options);
/* loopfilter alpha offset */
if (p_h264->loop_filter_alpha < 0) {
@@ -852,7 +901,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
reg = 0x00;
reg |= (p_h264->loop_filter_alpha & 0xF);
}
- WRITEL(reg, S5P_FIMV_E_H264_LF_ALPHA_OFFSET_V6);
+ WRITEL(reg, mfc_regs->e_h264_lf_alpha_offset);
/* loopfilter beta offset */
if (p_h264->loop_filter_beta < 0) {
@@ -862,28 +911,28 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
reg = 0x00;
reg |= (p_h264->loop_filter_beta & 0xF);
}
- WRITEL(reg, S5P_FIMV_E_H264_LF_BETA_OFFSET_V6);
+ WRITEL(reg, mfc_regs->e_h264_lf_beta_offset);
/* entropy coding mode */
- reg = READL(S5P_FIMV_E_H264_OPTIONS_V6);
+ reg = READL(mfc_regs->e_h264_options);
reg &= ~(0x1);
reg |= p_h264->entropy_mode & 0x1;
- WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_h264_options);
/* number of ref. picture */
- reg = READL(S5P_FIMV_E_H264_OPTIONS_V6);
+ reg = READL(mfc_regs->e_h264_options);
reg &= ~(0x1 << 7);
reg |= (((p_h264->num_ref_pic_4p - 1) & 0x1) << 7);
- WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_h264_options);
/* 8x8 transform enable */
- reg = READL(S5P_FIMV_E_H264_OPTIONS_V6);
+ reg = READL(mfc_regs->e_h264_options);
reg &= ~(0x3 << 12);
reg |= ((p_h264->_8x8_transform & 0x3) << 12);
- WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_h264_options);
/* macroblock adaptive scaling features */
- WRITEL(0x0, S5P_FIMV_E_MB_RC_CONFIG_V6);
+ WRITEL(0x0, mfc_regs->e_mb_rc_config);
if (p->rc_mb) {
reg = 0;
/** dark region */
@@ -894,92 +943,95 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
reg |= ((p_h264->rc_mb_static & 0x1) << 1);
/** high activity region */
reg |= p_h264->rc_mb_activity & 0x1;
- WRITEL(reg, S5P_FIMV_E_MB_RC_CONFIG_V6);
+ WRITEL(reg, mfc_regs->e_mb_rc_config);
}
/* aspect ratio VUI */
- reg = READL(S5P_FIMV_E_H264_OPTIONS_V6);
+ READL(mfc_regs->e_h264_options);
reg &= ~(0x1 << 5);
reg |= ((p_h264->vui_sar & 0x1) << 5);
- WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_h264_options);
- WRITEL(0x0, S5P_FIMV_E_ASPECT_RATIO_V6);
- WRITEL(0x0, S5P_FIMV_E_EXTENDED_SAR_V6);
+ WRITEL(0x0, mfc_regs->e_aspect_ratio);
+ WRITEL(0x0, mfc_regs->e_extended_sar);
if (p_h264->vui_sar) {
/* aspect ration IDC */
reg = 0;
reg |= p_h264->vui_sar_idc & 0xFF;
- WRITEL(reg, S5P_FIMV_E_ASPECT_RATIO_V6);
+ WRITEL(reg, mfc_regs->e_aspect_ratio);
if (p_h264->vui_sar_idc == 0xFF) {
/* extended SAR */
reg = 0;
reg |= (p_h264->vui_ext_sar_width & 0xFFFF) << 16;
reg |= p_h264->vui_ext_sar_height & 0xFFFF;
- WRITEL(reg, S5P_FIMV_E_EXTENDED_SAR_V6);
+ WRITEL(reg, mfc_regs->e_extended_sar);
}
}
/* intra picture period for H.264 open GOP */
/* control */
- reg = READL(S5P_FIMV_E_H264_OPTIONS_V6);
+ READL(mfc_regs->e_h264_options);
reg &= ~(0x1 << 4);
reg |= ((p_h264->open_gop & 0x1) << 4);
- WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_h264_options);
+
/* value */
- WRITEL(0x0, S5P_FIMV_E_H264_I_PERIOD_V6);
+ WRITEL(0x0, mfc_regs->e_h264_i_period);
if (p_h264->open_gop) {
reg = 0;
reg |= p_h264->open_gop_size & 0xFFFF;
- WRITEL(reg, S5P_FIMV_E_H264_I_PERIOD_V6);
+ WRITEL(reg, mfc_regs->e_h264_i_period);
}
/* 'WEIGHTED_BI_PREDICTION' for B is disable */
- reg = READL(S5P_FIMV_E_H264_OPTIONS_V6);
+ READL(mfc_regs->e_h264_options);
reg &= ~(0x3 << 9);
- WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_h264_options);
/* 'CONSTRAINED_INTRA_PRED_ENABLE' is disable */
- reg = READL(S5P_FIMV_E_H264_OPTIONS_V6);
+ READL(mfc_regs->e_h264_options);
reg &= ~(0x1 << 14);
- WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_h264_options);
/* ASO */
- reg = READL(S5P_FIMV_E_H264_OPTIONS_V6);
+ READL(mfc_regs->e_h264_options);
reg &= ~(0x1 << 6);
reg |= ((p_h264->aso & 0x1) << 6);
- WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_h264_options);
/* hier qp enable */
- reg = READL(S5P_FIMV_E_H264_OPTIONS_V6);
+ READL(mfc_regs->e_h264_options);
reg &= ~(0x1 << 8);
reg |= ((p_h264->open_gop & 0x1) << 8);
- WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_h264_options);
reg = 0;
if (p_h264->hier_qp && p_h264->hier_qp_layer) {
reg |= (p_h264->hier_qp_type & 0x1) << 0x3;
reg |= p_h264->hier_qp_layer & 0x7;
- WRITEL(reg, S5P_FIMV_E_H264_NUM_T_LAYER_V6);
+ WRITEL(reg, mfc_regs->e_h264_num_t_layer);
/* QP value for each layer */
- for (i = 0; i < (p_h264->hier_qp_layer & 0x7); i++)
+ for (i = 0; i < p_h264->hier_qp_layer &&
+ i < ARRAY_SIZE(p_h264->hier_qp_layer_qp); i++) {
WRITEL(p_h264->hier_qp_layer_qp[i],
- S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER0_V6 +
- i * 4);
+ mfc_regs->e_h264_hierarchical_qp_layer0
+ + i * 4);
+ }
}
/* number of coding layer should be zero when hierarchical is disable */
- WRITEL(reg, S5P_FIMV_E_H264_NUM_T_LAYER_V6);
+ WRITEL(reg, mfc_regs->e_h264_num_t_layer);
/* frame packing SEI generation */
- reg = READL(S5P_FIMV_E_H264_OPTIONS_V6);
+ READL(mfc_regs->e_h264_options);
reg &= ~(0x1 << 25);
reg |= ((p_h264->sei_frame_packing & 0x1) << 25);
- WRITEL(reg, S5P_FIMV_E_H264_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->e_h264_options);
if (p_h264->sei_frame_packing) {
reg = 0;
/** current frame0 flag */
reg |= ((p_h264->sei_fp_curr_frame_0 & 0x1) << 2);
/** arrangement type */
reg |= p_h264->sei_fp_arrangement_type & 0x3;
- WRITEL(reg, S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO_V6);
+ WRITEL(reg, mfc_regs->e_h264_frame_packing_sei_info);
}
if (p_h264->fmo) {
@@ -989,8 +1041,8 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
p_h264->fmo_slice_grp = 4;
for (i = 0; i < (p_h264->fmo_slice_grp & 0xF); i++)
WRITEL(p_h264->fmo_run_len[i] - 1,
- S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0_V6 +
- i * 4);
+ mfc_regs->e_h264_fmo_run_length_minus1_0
+ + i * 4);
break;
case V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_SCATTERED_SLICES:
if (p_h264->fmo_slice_grp > 4)
@@ -1001,10 +1053,10 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
if (p_h264->fmo_slice_grp > 2)
p_h264->fmo_slice_grp = 2;
WRITEL(p_h264->fmo_chg_dir & 0x1,
- S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR_V6);
+ mfc_regs->e_h264_fmo_slice_grp_change_dir);
/* the valid range is 0 ~ number of macroblocks -1 */
WRITEL(p_h264->fmo_chg_rate,
- S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1_V6);
+ mfc_regs->e_h264_fmo_slice_grp_change_rate_minus1);
break;
default:
mfc_err("Unsupported map type for FMO: %d\n",
@@ -1015,11 +1067,11 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
}
WRITEL(p_h264->fmo_map_type,
- S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE_V6);
+ mfc_regs->e_h264_fmo_slice_grp_map_type);
WRITEL(p_h264->fmo_slice_grp - 1,
- S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6);
+ mfc_regs->e_h264_fmo_num_slice_grp_minus1);
} else {
- WRITEL(0, S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6);
+ WRITEL(0, mfc_regs->e_h264_fmo_num_slice_grp_minus1);
}
mfc_debug_leave();
@@ -1030,6 +1082,7 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx)
static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
struct s5p_mfc_enc_params *p = &ctx->enc_params;
struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4;
unsigned int reg = 0;
@@ -1039,10 +1092,10 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
s5p_mfc_set_enc_params(ctx);
/* pictype : number of B */
- reg = READL(S5P_FIMV_E_GOP_CONFIG_V6);
+ reg = READL(mfc_regs->e_gop_config);
reg &= ~(0x3 << 16);
reg |= ((p->num_b_frame & 0x3) << 16);
- WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6);
+ WRITEL(reg, mfc_regs->e_gop_config);
/* profile & level */
reg = 0;
@@ -1050,18 +1103,19 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
reg |= ((p_mpeg4->level & 0xFF) << 8);
/** profile - 0 ~ 1 */
reg |= p_mpeg4->profile & 0x3F;
- WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6);
+ WRITEL(reg, mfc_regs->e_picture_profile);
/* rate control config. */
- reg = READL(S5P_FIMV_E_RC_CONFIG_V6);
+ reg = READL(mfc_regs->e_rc_config);
/** macroblock level rate control */
reg &= ~(0x1 << 8);
reg |= ((p->rc_mb & 0x1) << 8);
- WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
+ WRITEL(reg, mfc_regs->e_rc_config);
+
/** frame QP */
reg &= ~(0x3F);
reg |= p_mpeg4->rc_frame_qp & 0x3F;
- WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
+ WRITEL(reg, mfc_regs->e_rc_config);
/* max & min value of QP */
reg = 0;
@@ -1069,16 +1123,16 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
reg |= ((p_mpeg4->rc_max_qp & 0x3F) << 8);
/** min QP */
reg |= p_mpeg4->rc_min_qp & 0x3F;
- WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6);
+ WRITEL(reg, mfc_regs->e_rc_qp_bound);
/* other QPs */
- WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
+ WRITEL(0x0, mfc_regs->e_fixed_picture_qp);
if (!p->rc_frame && !p->rc_mb) {
reg = 0;
reg |= ((p_mpeg4->rc_b_frame_qp & 0x3F) << 16);
reg |= ((p_mpeg4->rc_p_frame_qp & 0x3F) << 8);
reg |= p_mpeg4->rc_frame_qp & 0x3F;
- WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
+ WRITEL(reg, mfc_regs->e_fixed_picture_qp);
}
/* frame rate */
@@ -1086,21 +1140,21 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
reg = 0;
reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
reg |= p->rc_framerate_denom & 0xFFFF;
- WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6);
+ WRITEL(reg, mfc_regs->e_rc_frame_rate);
}
/* vbv buffer size */
if (p->frame_skip_mode ==
V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
- WRITEL(p->vbv_size & 0xFFFF, S5P_FIMV_E_VBV_BUFFER_SIZE_V6);
+ WRITEL(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
if (p->rc_frame)
- WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6);
+ WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay);
}
/* Disable HEC */
- WRITEL(0x0, S5P_FIMV_E_MPEG4_OPTIONS_V6);
- WRITEL(0x0, S5P_FIMV_E_MPEG4_HEC_PERIOD_V6);
+ WRITEL(0x0, mfc_regs->e_mpeg4_options);
+ WRITEL(0x0, mfc_regs->e_mpeg4_hec_period);
mfc_debug_leave();
@@ -1110,6 +1164,7 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx)
static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
struct s5p_mfc_enc_params *p = &ctx->enc_params;
struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4;
unsigned int reg = 0;
@@ -1122,18 +1177,19 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
reg = 0;
/** profile */
reg |= (0x1 << 4);
- WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6);
+ WRITEL(reg, mfc_regs->e_picture_profile);
/* rate control config. */
- reg = READL(S5P_FIMV_E_RC_CONFIG_V6);
+ reg = READL(mfc_regs->e_rc_config);
/** macroblock level rate control */
reg &= ~(0x1 << 8);
reg |= ((p->rc_mb & 0x1) << 8);
- WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
+ WRITEL(reg, mfc_regs->e_rc_config);
+
/** frame QP */
reg &= ~(0x3F);
reg |= p_h263->rc_frame_qp & 0x3F;
- WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
+ WRITEL(reg, mfc_regs->e_rc_config);
/* max & min value of QP */
reg = 0;
@@ -1141,16 +1197,16 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
reg |= ((p_h263->rc_max_qp & 0x3F) << 8);
/** min QP */
reg |= p_h263->rc_min_qp & 0x3F;
- WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6);
+ WRITEL(reg, mfc_regs->e_rc_qp_bound);
/* other QPs */
- WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
+ WRITEL(0x0, mfc_regs->e_fixed_picture_qp);
if (!p->rc_frame && !p->rc_mb) {
reg = 0;
reg |= ((p_h263->rc_b_frame_qp & 0x3F) << 16);
reg |= ((p_h263->rc_p_frame_qp & 0x3F) << 8);
reg |= p_h263->rc_frame_qp & 0x3F;
- WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
+ WRITEL(reg, mfc_regs->e_fixed_picture_qp);
}
/* frame rate */
@@ -1158,16 +1214,16 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
reg = 0;
reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
reg |= p->rc_framerate_denom & 0xFFFF;
- WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6);
+ WRITEL(reg, mfc_regs->e_rc_frame_rate);
}
/* vbv buffer size */
if (p->frame_skip_mode ==
V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
- WRITEL(p->vbv_size & 0xFFFF, S5P_FIMV_E_VBV_BUFFER_SIZE_V6);
+ WRITEL(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
if (p->rc_frame)
- WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6);
+ WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay);
}
mfc_debug_leave();
@@ -1178,6 +1234,7 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx)
static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
struct s5p_mfc_enc_params *p = &ctx->enc_params;
struct s5p_mfc_vp8_enc_params *p_vp8 = &p->codec.vp8;
unsigned int reg = 0;
@@ -1188,57 +1245,57 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx)
s5p_mfc_set_enc_params(ctx);
/* pictype : number of B */
- reg = READL(S5P_FIMV_E_GOP_CONFIG_V6);
+ reg = READL(mfc_regs->e_gop_config);
reg &= ~(0x3 << 16);
reg |= ((p->num_b_frame & 0x3) << 16);
- WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6);
+ WRITEL(reg, mfc_regs->e_gop_config);
/* profile - 0 ~ 3 */
reg = p_vp8->profile & 0x3;
- WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6);
+ WRITEL(reg, mfc_regs->e_picture_profile);
/* rate control config. */
- reg = READL(S5P_FIMV_E_RC_CONFIG_V6);
+ reg = READL(mfc_regs->e_rc_config);
/** macroblock level rate control */
reg &= ~(0x1 << 8);
reg |= ((p->rc_mb & 0x1) << 8);
- WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
+ WRITEL(reg, mfc_regs->e_rc_config);
/* frame rate */
if (p->rc_frame && p->rc_framerate_num && p->rc_framerate_denom) {
reg = 0;
reg |= ((p->rc_framerate_num & 0xFFFF) << 16);
reg |= p->rc_framerate_denom & 0xFFFF;
- WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6);
+ WRITEL(reg, mfc_regs->e_rc_frame_rate);
}
/* frame QP */
reg &= ~(0x7F);
reg |= p_vp8->rc_frame_qp & 0x7F;
- WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
+ WRITEL(reg, mfc_regs->e_rc_config);
/* other QPs */
- WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
+ WRITEL(0x0, mfc_regs->e_fixed_picture_qp);
if (!p->rc_frame && !p->rc_mb) {
reg = 0;
reg |= ((p_vp8->rc_p_frame_qp & 0x7F) << 8);
reg |= p_vp8->rc_frame_qp & 0x7F;
- WRITEL(reg, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
+ WRITEL(reg, mfc_regs->e_fixed_picture_qp);
}
/* max QP */
reg = ((p_vp8->rc_max_qp & 0x7F) << 8);
/* min QP */
reg |= p_vp8->rc_min_qp & 0x7F;
- WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6);
+ WRITEL(reg, mfc_regs->e_rc_qp_bound);
/* vbv buffer size */
if (p->frame_skip_mode ==
V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
- WRITEL(p->vbv_size & 0xFFFF, S5P_FIMV_E_VBV_BUFFER_SIZE_V6);
+ WRITEL(p->vbv_size & 0xFFFF, mfc_regs->e_vbv_buffer_size);
if (p->rc_frame)
- WRITEL(p->vbv_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6);
+ WRITEL(p->vbv_delay, mfc_regs->e_vbv_init_delay);
}
/* VP8 specific params */
@@ -1260,7 +1317,7 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx)
}
reg |= (val & 0xF) << 3;
reg |= (p_vp8->num_ref & 0x2);
- WRITEL(reg, S5P_FIMV_E_VP8_OPTIONS_V7);
+ WRITEL(reg, mfc_regs->e_vp8_options);
mfc_debug_leave();
@@ -1271,6 +1328,7 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx)
static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
unsigned int reg = 0;
int fmo_aso_ctrl = 0;
@@ -1278,9 +1336,9 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
mfc_debug(2, "InstNo: %d/%d\n", ctx->inst_no,
S5P_FIMV_CH_SEQ_HEADER_V6);
mfc_debug(2, "BUFs: %08x %08x %08x\n",
- READL(S5P_FIMV_D_CPB_BUFFER_ADDR_V6),
- READL(S5P_FIMV_D_CPB_BUFFER_ADDR_V6),
- READL(S5P_FIMV_D_CPB_BUFFER_ADDR_V6));
+ READL(mfc_regs->d_cpb_buffer_addr),
+ READL(mfc_regs->d_cpb_buffer_addr),
+ READL(mfc_regs->d_cpb_buffer_addr));
/* FMO_ASO_CTRL - 0: Enable, 1: Disable */
reg |= (fmo_aso_ctrl << S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6);
@@ -1291,11 +1349,11 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
* set to negative value. */
if (ctx->display_delay >= 0) {
reg |= (0x1 << S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6);
- WRITEL(ctx->display_delay, S5P_FIMV_D_DISPLAY_DELAY_V6);
+ WRITEL(ctx->display_delay, mfc_regs->d_display_delay);
}
- if (IS_MFCV7(dev)) {
- WRITEL(reg, S5P_FIMV_D_DEC_OPTIONS_V6);
+ if (IS_MFCV7_PLUS(dev)) {
+ WRITEL(reg, mfc_regs->d_dec_options);
reg = 0;
}
@@ -1309,22 +1367,22 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV12MT_16X16)
reg |= (0x1 << S5P_FIMV_D_OPT_TILE_MODE_SHIFT_V6);
- if (IS_MFCV7(dev))
- WRITEL(reg, S5P_FIMV_D_INIT_BUFFER_OPTIONS_V7);
+ if (IS_MFCV7_PLUS(dev))
+ WRITEL(reg, mfc_regs->d_init_buffer_options);
else
- WRITEL(reg, S5P_FIMV_D_DEC_OPTIONS_V6);
+ WRITEL(reg, mfc_regs->d_dec_options);
/* 0: NV12(CbCr), 1: NV21(CrCb) */
if (ctx->dst_fmt->fourcc == V4L2_PIX_FMT_NV21M)
- WRITEL(0x1, S5P_FIMV_PIXEL_FORMAT_V6);
+ WRITEL(0x1, mfc_regs->pixel_format);
else
- WRITEL(0x0, S5P_FIMV_PIXEL_FORMAT_V6);
+ WRITEL(0x0, mfc_regs->pixel_format);
/* sei parse */
- WRITEL(ctx->sei_fp_parse & 0x1, S5P_FIMV_D_SEI_ENABLE_V6);
+ WRITEL(ctx->sei_fp_parse & 0x1, mfc_regs->d_sei_enable);
- WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6);
+ WRITEL(ctx->inst_no, mfc_regs->instance_id);
s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
S5P_FIMV_CH_SEQ_HEADER_V6, NULL);
@@ -1335,11 +1393,12 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
if (flush) {
dev->curr_ctx = ctx->num;
s5p_mfc_clean_ctx_int_flags(ctx);
- WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6);
+ WRITEL(ctx->inst_no, mfc_regs->instance_id);
s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
S5P_FIMV_H2R_CMD_FLUSH_V6, NULL);
}
@@ -1350,11 +1409,12 @@ static int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx,
enum s5p_mfc_decode_arg last_frame)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
- WRITEL(ctx->dec_dst_flag, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V6);
- WRITEL(ctx->slice_interface & 0x1, S5P_FIMV_D_SLICE_IF_ENABLE_V6);
+ WRITEL(ctx->dec_dst_flag, mfc_regs->d_available_dpb_flag_lower);
+ WRITEL(ctx->slice_interface & 0x1, mfc_regs->d_slice_if_enable);
- WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6);
+ WRITEL(ctx->inst_no, mfc_regs->instance_id);
/* Issue different commands to instance basing on whether it
* is the last frame or not. */
switch (last_frame) {
@@ -1378,6 +1438,7 @@ static int s5p_mfc_decode_one_frame_v6(struct s5p_mfc_ctx *ctx,
static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
if (ctx->codec_mode == S5P_MFC_CODEC_H264_ENC)
s5p_mfc_set_enc_params_h264(ctx);
@@ -1393,13 +1454,13 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
return -EINVAL;
}
- /* Set stride lengths */
- if (IS_MFCV7(dev)) {
- WRITEL(ctx->img_width, S5P_FIMV_E_SOURCE_FIRST_STRIDE_V7);
- WRITEL(ctx->img_width, S5P_FIMV_E_SOURCE_SECOND_STRIDE_V7);
+ /* Set stride lengths for v7 & above */
+ if (IS_MFCV7_PLUS(dev)) {
+ WRITEL(ctx->img_width, mfc_regs->e_source_first_plane_stride);
+ WRITEL(ctx->img_width, mfc_regs->e_source_second_plane_stride);
}
- WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6);
+ WRITEL(ctx->inst_no, mfc_regs->instance_id);
s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
S5P_FIMV_CH_SEQ_HEADER_V6, NULL);
@@ -1409,14 +1470,16 @@ static int s5p_mfc_init_encode_v6(struct s5p_mfc_ctx *ctx)
static int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
struct s5p_mfc_enc_params *p = &ctx->enc_params;
struct s5p_mfc_h264_enc_params *p_h264 = &p->codec.h264;
int i;
if (p_h264->aso) {
- for (i = 0; i < 8; i++)
+ for (i = 0; i < ARRAY_SIZE(p_h264->aso_slice_order); i++) {
WRITEL(p_h264->aso_slice_order[i],
- S5P_FIMV_E_H264_ASO_SLICE_ORDER_0_V6 + i * 4);
+ mfc_regs->e_h264_aso_slice_order_0 + i * 4);
+ }
}
return 0;
}
@@ -1425,6 +1488,7 @@ static int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx)
static int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
mfc_debug(2, "++\n");
@@ -1435,7 +1499,7 @@ static int s5p_mfc_encode_one_frame_v6(struct s5p_mfc_ctx *ctx)
s5p_mfc_set_slice_mode(ctx);
- WRITEL(ctx->inst_no, S5P_FIMV_INSTANCE_ID_V6);
+ WRITEL(ctx->inst_no, mfc_regs->instance_id);
s5p_mfc_hw_call(dev->mfc_cmds, cmd_host2risc, dev,
S5P_FIMV_CH_FRAME_START_V6, NULL);
@@ -1810,28 +1874,26 @@ static void s5p_mfc_cleanup_queue_v6(struct list_head *lh, struct vb2_queue *vq)
static void s5p_mfc_clear_int_flags_v6(struct s5p_mfc_dev *dev)
{
- mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6);
- mfc_write(dev, 0, S5P_FIMV_RISC2HOST_INT_V6);
+ const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs;
+ WRITEL(0, mfc_regs->risc2host_command);
+ WRITEL(0, mfc_regs->risc2host_int);
}
static void s5p_mfc_write_info_v6(struct s5p_mfc_ctx *ctx, unsigned int data,
unsigned int ofs)
{
- struct s5p_mfc_dev *dev = ctx->dev;
-
s5p_mfc_clock_on();
- WRITEL(data, ofs);
+ WRITEL(data, (void *)ofs);
s5p_mfc_clock_off();
}
static unsigned int
s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs)
{
- struct s5p_mfc_dev *dev = ctx->dev;
int ret;
s5p_mfc_clock_on();
- ret = READL(ofs);
+ ret = READL((void *)ofs);
s5p_mfc_clock_off();
return ret;
@@ -1839,50 +1901,51 @@ s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned int ofs)
static int s5p_mfc_get_dspl_y_adr_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6);
+ return READL(dev->mfc_regs->d_display_first_plane_addr);
}
static int s5p_mfc_get_dec_y_adr_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_D_DECODED_LUMA_ADDR_V6);
+ return READL(dev->mfc_regs->d_decoded_first_plane_addr);
}
static int s5p_mfc_get_dspl_status_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_D_DISPLAY_STATUS_V6);
+ return READL(dev->mfc_regs->d_display_status);
}
static int s5p_mfc_get_dec_status_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_D_DECODED_STATUS_V6);
+ return READL(dev->mfc_regs->d_decoded_status);
}
static int s5p_mfc_get_dec_frame_type_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_D_DECODED_FRAME_TYPE_V6) &
+ return READL(dev->mfc_regs->d_decoded_frame_type) &
S5P_FIMV_DECODE_FRAME_MASK_V6;
}
static int s5p_mfc_get_disp_frame_type_v6(struct s5p_mfc_ctx *ctx)
{
- return mfc_read(ctx->dev, S5P_FIMV_D_DISPLAY_FRAME_TYPE_V6) &
+ struct s5p_mfc_dev *dev = ctx->dev;
+ return READL(dev->mfc_regs->d_display_frame_type) &
S5P_FIMV_DECODE_FRAME_MASK_V6;
}
static int s5p_mfc_get_consumed_stream_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_D_DECODED_NAL_SIZE_V6);
+ return READL(dev->mfc_regs->d_decoded_nal_size);
}
static int s5p_mfc_get_int_reason_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_RISC2HOST_CMD_V6) &
+ return READL(dev->mfc_regs->risc2host_command) &
S5P_FIMV_RISC2HOST_CMD_MASK;
}
static int s5p_mfc_get_int_err_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_ERROR_CODE_V6);
+ return READL(dev->mfc_regs->error_code);
}
static int s5p_mfc_err_dec_v6(unsigned int err)
@@ -1897,82 +1960,323 @@ static int s5p_mfc_err_dspl_v6(unsigned int err)
static int s5p_mfc_get_img_width_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V6);
+ return READL(dev->mfc_regs->d_display_frame_width);
}
static int s5p_mfc_get_img_height_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V6);
+ return READL(dev->mfc_regs->d_display_frame_height);
}
static int s5p_mfc_get_dpb_count_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_D_MIN_NUM_DPB_V6);
+ return READL(dev->mfc_regs->d_min_num_dpb);
}
static int s5p_mfc_get_mv_count_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_D_MIN_NUM_MV_V6);
+ return READL(dev->mfc_regs->d_min_num_mv);
}
static int s5p_mfc_get_inst_no_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_RET_INSTANCE_ID_V6);
+ return READL(dev->mfc_regs->ret_instance_id);
}
static int s5p_mfc_get_enc_dpb_count_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_E_NUM_DPB_V6);
+ return READL(dev->mfc_regs->e_num_dpb);
}
static int s5p_mfc_get_enc_strm_size_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_E_STREAM_SIZE_V6);
+ return READL(dev->mfc_regs->e_stream_size);
}
static int s5p_mfc_get_enc_slice_type_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_E_SLICE_TYPE_V6);
+ return READL(dev->mfc_regs->e_slice_type);
}
static int s5p_mfc_get_enc_pic_count_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_E_PICTURE_COUNT_V6);
+ return READL(dev->mfc_regs->e_picture_count);
}
static int s5p_mfc_get_sei_avail_status_v6(struct s5p_mfc_ctx *ctx)
{
- return mfc_read(ctx->dev, S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V6);
+ struct s5p_mfc_dev *dev = ctx->dev;
+ return READL(dev->mfc_regs->d_frame_pack_sei_avail);
}
static int s5p_mfc_get_mvc_num_views_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_D_MVC_NUM_VIEWS_V6);
+ return READL(dev->mfc_regs->d_mvc_num_views);
}
static int s5p_mfc_get_mvc_view_id_v6(struct s5p_mfc_dev *dev)
{
- return mfc_read(dev, S5P_FIMV_D_MVC_VIEW_ID_V6);
+ return READL(dev->mfc_regs->d_mvc_view_id);
}
static unsigned int s5p_mfc_get_pic_type_top_v6(struct s5p_mfc_ctx *ctx)
{
- return s5p_mfc_read_info_v6(ctx, PIC_TIME_TOP_V6);
+ return s5p_mfc_read_info_v6(ctx,
+ (unsigned int) ctx->dev->mfc_regs->d_ret_picture_tag_top);
}
static unsigned int s5p_mfc_get_pic_type_bot_v6(struct s5p_mfc_ctx *ctx)
{
- return s5p_mfc_read_info_v6(ctx, PIC_TIME_BOT_V6);
+ return s5p_mfc_read_info_v6(ctx,
+ (unsigned int) ctx->dev->mfc_regs->d_ret_picture_tag_bot);
}
static unsigned int s5p_mfc_get_crop_info_h_v6(struct s5p_mfc_ctx *ctx)
{
- return s5p_mfc_read_info_v6(ctx, CROP_INFO_H_V6);
+ return s5p_mfc_read_info_v6(ctx,
+ (unsigned int) ctx->dev->mfc_regs->d_display_crop_info1);
}
static unsigned int s5p_mfc_get_crop_info_v_v6(struct s5p_mfc_ctx *ctx)
{
- return s5p_mfc_read_info_v6(ctx, CROP_INFO_V_V6);
+ return s5p_mfc_read_info_v6(ctx,
+ (unsigned int) ctx->dev->mfc_regs->d_display_crop_info2);
+}
+
+static struct s5p_mfc_regs mfc_regs;
+
+/* Initialize registers for MFC v6 onwards */
+const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev)
+{
+ memset(&mfc_regs, 0, sizeof(mfc_regs));
+
+#define S5P_MFC_REG_ADDR(dev, reg) ((dev)->regs_base + (reg))
+#define R(m, r) mfc_regs.m = S5P_MFC_REG_ADDR(dev, r)
+ /* codec common registers */
+ R(risc_on, S5P_FIMV_RISC_ON_V6);
+ R(risc2host_int, S5P_FIMV_RISC2HOST_INT_V6);
+ R(host2risc_int, S5P_FIMV_HOST2RISC_INT_V6);
+ R(risc_base_address, S5P_FIMV_RISC_BASE_ADDRESS_V6);
+ R(mfc_reset, S5P_FIMV_MFC_RESET_V6);
+ R(host2risc_command, S5P_FIMV_HOST2RISC_CMD_V6);
+ R(risc2host_command, S5P_FIMV_RISC2HOST_CMD_V6);
+ R(firmware_version, S5P_FIMV_FW_VERSION_V6);
+ R(instance_id, S5P_FIMV_INSTANCE_ID_V6);
+ R(codec_type, S5P_FIMV_CODEC_TYPE_V6);
+ R(context_mem_addr, S5P_FIMV_CONTEXT_MEM_ADDR_V6);
+ R(context_mem_size, S5P_FIMV_CONTEXT_MEM_SIZE_V6);
+ R(pixel_format, S5P_FIMV_PIXEL_FORMAT_V6);
+ R(ret_instance_id, S5P_FIMV_RET_INSTANCE_ID_V6);
+ R(error_code, S5P_FIMV_ERROR_CODE_V6);
+
+ /* decoder registers */
+ R(d_crc_ctrl, S5P_FIMV_D_CRC_CTRL_V6);
+ R(d_dec_options, S5P_FIMV_D_DEC_OPTIONS_V6);
+ R(d_display_delay, S5P_FIMV_D_DISPLAY_DELAY_V6);
+ R(d_sei_enable, S5P_FIMV_D_SEI_ENABLE_V6);
+ R(d_min_num_dpb, S5P_FIMV_D_MIN_NUM_DPB_V6);
+ R(d_min_num_mv, S5P_FIMV_D_MIN_NUM_MV_V6);
+ R(d_mvc_num_views, S5P_FIMV_D_MVC_NUM_VIEWS_V6);
+ R(d_num_dpb, S5P_FIMV_D_NUM_DPB_V6);
+ R(d_num_mv, S5P_FIMV_D_NUM_MV_V6);
+ R(d_init_buffer_options, S5P_FIMV_D_INIT_BUFFER_OPTIONS_V6);
+ R(d_first_plane_dpb_size, S5P_FIMV_D_LUMA_DPB_SIZE_V6);
+ R(d_second_plane_dpb_size, S5P_FIMV_D_CHROMA_DPB_SIZE_V6);
+ R(d_mv_buffer_size, S5P_FIMV_D_MV_BUFFER_SIZE_V6);
+ R(d_first_plane_dpb, S5P_FIMV_D_LUMA_DPB_V6);
+ R(d_second_plane_dpb, S5P_FIMV_D_CHROMA_DPB_V6);
+ R(d_mv_buffer, S5P_FIMV_D_MV_BUFFER_V6);
+ R(d_scratch_buffer_addr, S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V6);
+ R(d_scratch_buffer_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V6);
+ R(d_cpb_buffer_addr, S5P_FIMV_D_CPB_BUFFER_ADDR_V6);
+ R(d_cpb_buffer_size, S5P_FIMV_D_CPB_BUFFER_SIZE_V6);
+ R(d_available_dpb_flag_lower, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V6);
+ R(d_cpb_buffer_offset, S5P_FIMV_D_CPB_BUFFER_OFFSET_V6);
+ R(d_slice_if_enable, S5P_FIMV_D_SLICE_IF_ENABLE_V6);
+ R(d_stream_data_size, S5P_FIMV_D_STREAM_DATA_SIZE_V6);
+ R(d_display_frame_width, S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V6);
+ R(d_display_frame_height, S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V6);
+ R(d_display_status, S5P_FIMV_D_DISPLAY_STATUS_V6);
+ R(d_display_first_plane_addr, S5P_FIMV_D_DISPLAY_LUMA_ADDR_V6);
+ R(d_display_second_plane_addr, S5P_FIMV_D_DISPLAY_CHROMA_ADDR_V6);
+ R(d_display_frame_type, S5P_FIMV_D_DISPLAY_FRAME_TYPE_V6);
+ R(d_display_crop_info1, S5P_FIMV_D_DISPLAY_CROP_INFO1_V6);
+ R(d_display_crop_info2, S5P_FIMV_D_DISPLAY_CROP_INFO2_V6);
+ R(d_display_aspect_ratio, S5P_FIMV_D_DISPLAY_ASPECT_RATIO_V6);
+ R(d_display_extended_ar, S5P_FIMV_D_DISPLAY_EXTENDED_AR_V6);
+ R(d_decoded_status, S5P_FIMV_D_DECODED_STATUS_V6);
+ R(d_decoded_first_plane_addr, S5P_FIMV_D_DECODED_LUMA_ADDR_V6);
+ R(d_decoded_second_plane_addr, S5P_FIMV_D_DECODED_CHROMA_ADDR_V6);
+ R(d_decoded_frame_type, S5P_FIMV_D_DECODED_FRAME_TYPE_V6);
+ R(d_decoded_nal_size, S5P_FIMV_D_DECODED_NAL_SIZE_V6);
+ R(d_ret_picture_tag_top, S5P_FIMV_D_RET_PICTURE_TAG_TOP_V6);
+ R(d_ret_picture_tag_bot, S5P_FIMV_D_RET_PICTURE_TAG_BOT_V6);
+ R(d_h264_info, S5P_FIMV_D_H264_INFO_V6);
+ R(d_mvc_view_id, S5P_FIMV_D_MVC_VIEW_ID_V6);
+ R(d_frame_pack_sei_avail, S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V6);
+
+ /* encoder registers */
+ R(e_frame_width, S5P_FIMV_E_FRAME_WIDTH_V6);
+ R(e_frame_height, S5P_FIMV_E_FRAME_HEIGHT_V6);
+ R(e_cropped_frame_width, S5P_FIMV_E_CROPPED_FRAME_WIDTH_V6);
+ R(e_cropped_frame_height, S5P_FIMV_E_CROPPED_FRAME_HEIGHT_V6);
+ R(e_frame_crop_offset, S5P_FIMV_E_FRAME_CROP_OFFSET_V6);
+ R(e_enc_options, S5P_FIMV_E_ENC_OPTIONS_V6);
+ R(e_picture_profile, S5P_FIMV_E_PICTURE_PROFILE_V6);
+ R(e_vbv_buffer_size, S5P_FIMV_E_VBV_BUFFER_SIZE_V6);
+ R(e_vbv_init_delay, S5P_FIMV_E_VBV_INIT_DELAY_V6);
+ R(e_fixed_picture_qp, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
+ R(e_rc_config, S5P_FIMV_E_RC_CONFIG_V6);
+ R(e_rc_qp_bound, S5P_FIMV_E_RC_QP_BOUND_V6);
+ R(e_rc_mode, S5P_FIMV_E_RC_RPARAM_V6);
+ R(e_mb_rc_config, S5P_FIMV_E_MB_RC_CONFIG_V6);
+ R(e_padding_ctrl, S5P_FIMV_E_PADDING_CTRL_V6);
+ R(e_mv_hor_range, S5P_FIMV_E_MV_HOR_RANGE_V6);
+ R(e_mv_ver_range, S5P_FIMV_E_MV_VER_RANGE_V6);
+ R(e_num_dpb, S5P_FIMV_E_NUM_DPB_V6);
+ R(e_luma_dpb, S5P_FIMV_E_LUMA_DPB_V6);
+ R(e_chroma_dpb, S5P_FIMV_E_CHROMA_DPB_V6);
+ R(e_me_buffer, S5P_FIMV_E_ME_BUFFER_V6);
+ R(e_scratch_buffer_addr, S5P_FIMV_E_SCRATCH_BUFFER_ADDR_V6);
+ R(e_scratch_buffer_size, S5P_FIMV_E_SCRATCH_BUFFER_SIZE_V6);
+ R(e_tmv_buffer0, S5P_FIMV_E_TMV_BUFFER0_V6);
+ R(e_tmv_buffer1, S5P_FIMV_E_TMV_BUFFER1_V6);
+ R(e_source_first_plane_addr, S5P_FIMV_E_SOURCE_LUMA_ADDR_V6);
+ R(e_source_second_plane_addr, S5P_FIMV_E_SOURCE_CHROMA_ADDR_V6);
+ R(e_stream_buffer_addr, S5P_FIMV_E_STREAM_BUFFER_ADDR_V6);
+ R(e_stream_buffer_size, S5P_FIMV_E_STREAM_BUFFER_SIZE_V6);
+ R(e_roi_buffer_addr, S5P_FIMV_E_ROI_BUFFER_ADDR_V6);
+ R(e_param_change, S5P_FIMV_E_PARAM_CHANGE_V6);
+ R(e_ir_size, S5P_FIMV_E_IR_SIZE_V6);
+ R(e_gop_config, S5P_FIMV_E_GOP_CONFIG_V6);
+ R(e_mslice_mode, S5P_FIMV_E_MSLICE_MODE_V6);
+ R(e_mslice_size_mb, S5P_FIMV_E_MSLICE_SIZE_MB_V6);
+ R(e_mslice_size_bits, S5P_FIMV_E_MSLICE_SIZE_BITS_V6);
+ R(e_frame_insertion, S5P_FIMV_E_FRAME_INSERTION_V6);
+ R(e_rc_frame_rate, S5P_FIMV_E_RC_FRAME_RATE_V6);
+ R(e_rc_bit_rate, S5P_FIMV_E_RC_BIT_RATE_V6);
+ R(e_rc_roi_ctrl, S5P_FIMV_E_RC_ROI_CTRL_V6);
+ R(e_picture_tag, S5P_FIMV_E_PICTURE_TAG_V6);
+ R(e_bit_count_enable, S5P_FIMV_E_BIT_COUNT_ENABLE_V6);
+ R(e_max_bit_count, S5P_FIMV_E_MAX_BIT_COUNT_V6);
+ R(e_min_bit_count, S5P_FIMV_E_MIN_BIT_COUNT_V6);
+ R(e_metadata_buffer_addr, S5P_FIMV_E_METADATA_BUFFER_ADDR_V6);
+ R(e_metadata_buffer_size, S5P_FIMV_E_METADATA_BUFFER_SIZE_V6);
+ R(e_encoded_source_first_plane_addr,
+ S5P_FIMV_E_ENCODED_SOURCE_LUMA_ADDR_V6);
+ R(e_encoded_source_second_plane_addr,
+ S5P_FIMV_E_ENCODED_SOURCE_CHROMA_ADDR_V6);
+ R(e_stream_size, S5P_FIMV_E_STREAM_SIZE_V6);
+ R(e_slice_type, S5P_FIMV_E_SLICE_TYPE_V6);
+ R(e_picture_count, S5P_FIMV_E_PICTURE_COUNT_V6);
+ R(e_ret_picture_tag, S5P_FIMV_E_RET_PICTURE_TAG_V6);
+ R(e_recon_luma_dpb_addr, S5P_FIMV_E_RECON_LUMA_DPB_ADDR_V6);
+ R(e_recon_chroma_dpb_addr, S5P_FIMV_E_RECON_CHROMA_DPB_ADDR_V6);
+ R(e_mpeg4_options, S5P_FIMV_E_MPEG4_OPTIONS_V6);
+ R(e_mpeg4_hec_period, S5P_FIMV_E_MPEG4_HEC_PERIOD_V6);
+ R(e_aspect_ratio, S5P_FIMV_E_ASPECT_RATIO_V6);
+ R(e_extended_sar, S5P_FIMV_E_EXTENDED_SAR_V6);
+ R(e_h264_options, S5P_FIMV_E_H264_OPTIONS_V6);
+ R(e_h264_lf_alpha_offset, S5P_FIMV_E_H264_LF_ALPHA_OFFSET_V6);
+ R(e_h264_lf_beta_offset, S5P_FIMV_E_H264_LF_BETA_OFFSET_V6);
+ R(e_h264_i_period, S5P_FIMV_E_H264_I_PERIOD_V6);
+ R(e_h264_fmo_slice_grp_map_type,
+ S5P_FIMV_E_H264_FMO_SLICE_GRP_MAP_TYPE_V6);
+ R(e_h264_fmo_num_slice_grp_minus1,
+ S5P_FIMV_E_H264_FMO_NUM_SLICE_GRP_MINUS1_V6);
+ R(e_h264_fmo_slice_grp_change_dir,
+ S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_DIR_V6);
+ R(e_h264_fmo_slice_grp_change_rate_minus1,
+ S5P_FIMV_E_H264_FMO_SLICE_GRP_CHANGE_RATE_MINUS1_V6);
+ R(e_h264_fmo_run_length_minus1_0,
+ S5P_FIMV_E_H264_FMO_RUN_LENGTH_MINUS1_0_V6);
+ R(e_h264_aso_slice_order_0, S5P_FIMV_E_H264_ASO_SLICE_ORDER_0_V6);
+ R(e_h264_num_t_layer, S5P_FIMV_E_H264_NUM_T_LAYER_V6);
+ R(e_h264_hierarchical_qp_layer0,
+ S5P_FIMV_E_H264_HIERARCHICAL_QP_LAYER0_V6);
+ R(e_h264_frame_packing_sei_info,
+ S5P_FIMV_E_H264_FRAME_PACKING_SEI_INFO_V6);
+
+ if (!IS_MFCV7_PLUS(dev))
+ goto done;
+
+ /* Initialize registers used in MFC v7+ */
+ R(e_source_first_plane_addr, S5P_FIMV_E_SOURCE_FIRST_ADDR_V7);
+ R(e_source_second_plane_addr, S5P_FIMV_E_SOURCE_SECOND_ADDR_V7);
+ R(e_source_third_plane_addr, S5P_FIMV_E_SOURCE_THIRD_ADDR_V7);
+ R(e_source_first_plane_stride, S5P_FIMV_E_SOURCE_FIRST_STRIDE_V7);
+ R(e_source_second_plane_stride, S5P_FIMV_E_SOURCE_SECOND_STRIDE_V7);
+ R(e_source_third_plane_stride, S5P_FIMV_E_SOURCE_THIRD_STRIDE_V7);
+ R(e_encoded_source_first_plane_addr,
+ S5P_FIMV_E_ENCODED_SOURCE_FIRST_ADDR_V7);
+ R(e_encoded_source_second_plane_addr,
+ S5P_FIMV_E_ENCODED_SOURCE_SECOND_ADDR_V7);
+ R(e_vp8_options, S5P_FIMV_E_VP8_OPTIONS_V7);
+
+ if (!IS_MFCV8(dev))
+ goto done;
+
+ /* Initialize registers used in MFC v8 only.
+ * Also, over-write the registers which have
+ * a different offset for MFC v8. */
+ R(d_stream_data_size, S5P_FIMV_D_STREAM_DATA_SIZE_V8);
+ R(d_cpb_buffer_addr, S5P_FIMV_D_CPB_BUFFER_ADDR_V8);
+ R(d_cpb_buffer_size, S5P_FIMV_D_CPB_BUFFER_SIZE_V8);
+ R(d_cpb_buffer_offset, S5P_FIMV_D_CPB_BUFFER_OFFSET_V8);
+ R(d_first_plane_dpb_size, S5P_FIMV_D_FIRST_PLANE_DPB_SIZE_V8);
+ R(d_second_plane_dpb_size, S5P_FIMV_D_SECOND_PLANE_DPB_SIZE_V8);
+ R(d_scratch_buffer_addr, S5P_FIMV_D_SCRATCH_BUFFER_ADDR_V8);
+ R(d_scratch_buffer_size, S5P_FIMV_D_SCRATCH_BUFFER_SIZE_V8);
+ R(d_first_plane_dpb_stride_size,
+ S5P_FIMV_D_FIRST_PLANE_DPB_STRIDE_SIZE_V8);
+ R(d_second_plane_dpb_stride_size,
+ S5P_FIMV_D_SECOND_PLANE_DPB_STRIDE_SIZE_V8);
+ R(d_mv_buffer_size, S5P_FIMV_D_MV_BUFFER_SIZE_V8);
+ R(d_num_mv, S5P_FIMV_D_NUM_MV_V8);
+ R(d_first_plane_dpb, S5P_FIMV_D_FIRST_PLANE_DPB_V8);
+ R(d_second_plane_dpb, S5P_FIMV_D_SECOND_PLANE_DPB_V8);
+ R(d_mv_buffer, S5P_FIMV_D_MV_BUFFER_V8);
+ R(d_init_buffer_options, S5P_FIMV_D_INIT_BUFFER_OPTIONS_V8);
+ R(d_available_dpb_flag_lower, S5P_FIMV_D_AVAILABLE_DPB_FLAG_LOWER_V8);
+ R(d_slice_if_enable, S5P_FIMV_D_SLICE_IF_ENABLE_V8);
+ R(d_display_first_plane_addr, S5P_FIMV_D_DISPLAY_FIRST_PLANE_ADDR_V8);
+ R(d_display_second_plane_addr, S5P_FIMV_D_DISPLAY_SECOND_PLANE_ADDR_V8);
+ R(d_decoded_first_plane_addr, S5P_FIMV_D_DECODED_FIRST_PLANE_ADDR_V8);
+ R(d_decoded_second_plane_addr, S5P_FIMV_D_DECODED_SECOND_PLANE_ADDR_V8);
+ R(d_display_status, S5P_FIMV_D_DISPLAY_STATUS_V8);
+ R(d_decoded_status, S5P_FIMV_D_DECODED_STATUS_V8);
+ R(d_decoded_frame_type, S5P_FIMV_D_DECODED_FRAME_TYPE_V8);
+ R(d_display_frame_type, S5P_FIMV_D_DISPLAY_FRAME_TYPE_V8);
+ R(d_decoded_nal_size, S5P_FIMV_D_DECODED_NAL_SIZE_V8);
+ R(d_display_frame_width, S5P_FIMV_D_DISPLAY_FRAME_WIDTH_V8);
+ R(d_display_frame_height, S5P_FIMV_D_DISPLAY_FRAME_HEIGHT_V8);
+ R(d_frame_pack_sei_avail, S5P_FIMV_D_FRAME_PACK_SEI_AVAIL_V8);
+ R(d_mvc_num_views, S5P_FIMV_D_MVC_NUM_VIEWS_V8);
+ R(d_mvc_view_id, S5P_FIMV_D_MVC_VIEW_ID_V8);
+ R(d_ret_picture_tag_top, S5P_FIMV_D_RET_PICTURE_TAG_TOP_V8);
+ R(d_ret_picture_tag_bot, S5P_FIMV_D_RET_PICTURE_TAG_BOT_V8);
+ R(d_display_crop_info1, S5P_FIMV_D_DISPLAY_CROP_INFO1_V8);
+ R(d_display_crop_info2, S5P_FIMV_D_DISPLAY_CROP_INFO2_V8);
+
+ /* encoder registers */
+ R(e_padding_ctrl, S5P_FIMV_E_PADDING_CTRL_V8);
+ R(e_rc_config, S5P_FIMV_E_RC_CONFIG_V8);
+ R(e_rc_mode, S5P_FIMV_E_RC_RPARAM_V8);
+ R(e_mv_hor_range, S5P_FIMV_E_MV_HOR_RANGE_V8);
+ R(e_mv_ver_range, S5P_FIMV_E_MV_VER_RANGE_V8);
+ R(e_rc_qp_bound, S5P_FIMV_E_RC_QP_BOUND_V8);
+ R(e_fixed_picture_qp, S5P_FIMV_E_FIXED_PICTURE_QP_V8);
+ R(e_vbv_buffer_size, S5P_FIMV_E_VBV_BUFFER_SIZE_V8);
+ R(e_vbv_init_delay, S5P_FIMV_E_VBV_INIT_DELAY_V8);
+ R(e_mb_rc_config, S5P_FIMV_E_MB_RC_CONFIG_V8);
+ R(e_aspect_ratio, S5P_FIMV_E_ASPECT_RATIO_V8);
+ R(e_extended_sar, S5P_FIMV_E_EXTENDED_SAR_V8);
+ R(e_h264_options, S5P_FIMV_E_H264_OPTIONS_V8);
+
+done:
+ return &mfc_regs;
+#undef S5P_MFC_REG_ADDR
+#undef R
}
/* Initialize opr function pointers for MFC v6 */
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h
index ab164efa127e..80558484bb40 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.h
@@ -40,11 +40,6 @@
#define FRAME_DELTA_H264_H263 1
#define TIGHT_CBR_MAX 10
-/* Definitions for shared memory compatibility */
-#define PIC_TIME_TOP_V6 S5P_FIMV_D_RET_PICTURE_TAG_TOP_V6
-#define PIC_TIME_BOT_V6 S5P_FIMV_D_RET_PICTURE_TAG_BOT_V6
-#define CROP_INFO_H_V6 S5P_FIMV_D_DISPLAY_CROP_INFO1_V6
-#define CROP_INFO_V_V6 S5P_FIMV_D_DISPLAY_CROP_INFO2_V6
-
struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void);
+const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev);
#endif /* S5P_MFC_OPR_V6_H_ */
diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c
index 534722c04ec5..754740f4b671 100644
--- a/drivers/media/platform/s5p-tv/hdmi_drv.c
+++ b/drivers/media/platform/s5p-tv/hdmi_drv.c
@@ -674,6 +674,8 @@ static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
static int hdmi_enum_dv_timings(struct v4l2_subdev *sd,
struct v4l2_enum_dv_timings *timings)
{
+ if (timings->pad != 0)
+ return -EINVAL;
if (timings->index >= ARRAY_SIZE(hdmi_timings))
return -EINVAL;
timings->timings = hdmi_timings[timings->index].dv_timings;
@@ -687,8 +689,11 @@ static int hdmi_dv_timings_cap(struct v4l2_subdev *sd,
{
struct hdmi_device *hdev = sd_to_hdmi_dev(sd);
+ if (cap->pad != 0)
+ return -EINVAL;
+
/* Let the phy fill in the pixelclock range */
- v4l2_subdev_call(hdev->phy_sd, video, dv_timings_cap, cap);
+ v4l2_subdev_call(hdev->phy_sd, pad, dv_timings_cap, cap);
cap->type = V4L2_DV_BT_656_1120;
cap->bt.min_width = 720;
cap->bt.max_width = 1920;
@@ -707,12 +712,15 @@ static const struct v4l2_subdev_core_ops hdmi_sd_core_ops = {
static const struct v4l2_subdev_video_ops hdmi_sd_video_ops = {
.s_dv_timings = hdmi_s_dv_timings,
.g_dv_timings = hdmi_g_dv_timings,
- .enum_dv_timings = hdmi_enum_dv_timings,
- .dv_timings_cap = hdmi_dv_timings_cap,
.g_mbus_fmt = hdmi_g_mbus_fmt,
.s_stream = hdmi_s_stream,
};
+static const struct v4l2_subdev_pad_ops hdmi_sd_pad_ops = {
+ .enum_dv_timings = hdmi_enum_dv_timings,
+ .dv_timings_cap = hdmi_dv_timings_cap,
+};
+
static const struct v4l2_subdev_ops hdmi_sd_ops = {
.core = &hdmi_sd_core_ops,
.video = &hdmi_sd_video_ops,
diff --git a/drivers/media/platform/s5p-tv/hdmiphy_drv.c b/drivers/media/platform/s5p-tv/hdmiphy_drv.c
index e19a0af1ea4f..c2f2e35642f2 100644
--- a/drivers/media/platform/s5p-tv/hdmiphy_drv.c
+++ b/drivers/media/platform/s5p-tv/hdmiphy_drv.c
@@ -225,6 +225,9 @@ static int hdmiphy_s_dv_timings(struct v4l2_subdev *sd,
static int hdmiphy_dv_timings_cap(struct v4l2_subdev *sd,
struct v4l2_dv_timings_cap *cap)
{
+ if (cap->pad != 0)
+ return -EINVAL;
+
cap->type = V4L2_DV_BT_656_1120;
/* The phy only determines the pixelclock, leave the other values
* at 0 to signify that we have no information for them. */
@@ -259,13 +262,17 @@ static const struct v4l2_subdev_core_ops hdmiphy_core_ops = {
static const struct v4l2_subdev_video_ops hdmiphy_video_ops = {
.s_dv_timings = hdmiphy_s_dv_timings,
- .dv_timings_cap = hdmiphy_dv_timings_cap,
.s_stream = hdmiphy_s_stream,
};
+static const struct v4l2_subdev_pad_ops hdmiphy_pad_ops = {
+ .dv_timings_cap = hdmiphy_dv_timings_cap,
+};
+
static const struct v4l2_subdev_ops hdmiphy_ops = {
.core = &hdmiphy_core_ops,
.video = &hdmiphy_video_ops,
+ .pad = &hdmiphy_pad_ops,
};
static int hdmiphy_probe(struct i2c_client *client,
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c
index a1ce55fd30f3..8a8dbc8fdfde 100644
--- a/drivers/media/platform/s5p-tv/mixer_video.c
+++ b/drivers/media/platform/s5p-tv/mixer_video.c
@@ -509,9 +509,11 @@ static int mxr_enum_dv_timings(struct file *file, void *fh,
struct mxr_device *mdev = layer->mdev;
int ret;
+ timings->pad = 0;
+
/* lock protects from changing sd_out */
mutex_lock(&mdev->mutex);
- ret = v4l2_subdev_call(to_outsd(mdev), video, enum_dv_timings, timings);
+ ret = v4l2_subdev_call(to_outsd(mdev), pad, enum_dv_timings, timings);
mutex_unlock(&mdev->mutex);
return ret ? -EINVAL : 0;
@@ -567,9 +569,11 @@ static int mxr_dv_timings_cap(struct file *file, void *fh,
struct mxr_device *mdev = layer->mdev;
int ret;
+ cap->pad = 0;
+
/* lock protects from changing sd_out */
mutex_lock(&mdev->mutex);
- ret = v4l2_subdev_call(to_outsd(mdev), video, dv_timings_cap, cap);
+ ret = v4l2_subdev_call(to_outsd(mdev), pad, dv_timings_cap, cap);
mutex_unlock(&mdev->mutex);
return ret ? -EINVAL : 0;
@@ -985,7 +989,7 @@ static void mxr_watchdog(unsigned long arg)
spin_unlock_irqrestore(&layer->enq_slock, flags);
}
-static int stop_streaming(struct vb2_queue *vq)
+static void stop_streaming(struct vb2_queue *vq)
{
struct mxr_layer *layer = vb2_get_drv_priv(vq);
struct mxr_device *mdev = layer->mdev;
@@ -1031,7 +1035,6 @@ static int stop_streaming(struct vb2_queue *vq)
mxr_streamer_put(mdev);
/* allow changes in output configuration */
mxr_output_put(mdev);
- return 0;
}
static struct vb2_ops mxr_video_qops = {
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c
index f0b6c900034d..38c723aca438 100644
--- a/drivers/media/platform/soc_camera/atmel-isi.c
+++ b/drivers/media/platform/soc_camera/atmel-isi.c
@@ -406,7 +406,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
}
/* abort streaming and wait for last buffer */
-static int stop_streaming(struct vb2_queue *vq)
+static void stop_streaming(struct vb2_queue *vq)
{
struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -433,7 +433,7 @@ static int stop_streaming(struct vb2_queue *vq)
if (time_after(jiffies, timeout)) {
dev_err(icd->parent,
"Timeout waiting for finishing codec request\n");
- return -ETIMEDOUT;
+ return;
}
/* Disable interrupts */
@@ -444,8 +444,6 @@ static int stop_streaming(struct vb2_queue *vq)
ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE);
if (ret < 0)
dev_err(icd->parent, "Disable ISI timed out\n");
-
- return ret;
}
static struct vb2_ops isi_video_qops = {
diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c
index 3e844803bdca..b40bc2e5ba47 100644
--- a/drivers/media/platform/soc_camera/mx2_camera.c
+++ b/drivers/media/platform/soc_camera/mx2_camera.c
@@ -741,7 +741,7 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count)
return 0;
}
-static int mx2_stop_streaming(struct vb2_queue *q)
+static void mx2_stop_streaming(struct vb2_queue *q)
{
struct soc_camera_device *icd = soc_camera_from_vb2q(q);
struct soc_camera_host *ici =
@@ -773,8 +773,6 @@ static int mx2_stop_streaming(struct vb2_queue *q)
dma_free_coherent(ici->v4l2_dev.dev,
pcdev->discard_size, b, pcdev->discard_buffer_dma);
-
- return 0;
}
static struct vb2_ops mx2_videobuf_ops = {
diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c
index 9ed81ac6881c..83315dfeef62 100644
--- a/drivers/media/platform/soc_camera/mx3_camera.c
+++ b/drivers/media/platform/soc_camera/mx3_camera.c
@@ -406,7 +406,7 @@ static int mx3_videobuf_init(struct vb2_buffer *vb)
return 0;
}
-static int mx3_stop_streaming(struct vb2_queue *q)
+static void mx3_stop_streaming(struct vb2_queue *q)
{
struct soc_camera_device *icd = soc_camera_from_vb2q(q);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -430,8 +430,6 @@ static int mx3_stop_streaming(struct vb2_queue *q)
}
spin_unlock_irqrestore(&mx3_cam->lock, flags);
-
- return 0;
}
static struct vb2_ops mx3_videobuf_ops = {
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
index 704eee766487..e594230e84d3 100644
--- a/drivers/media/platform/soc_camera/rcar_vin.c
+++ b/drivers/media/platform/soc_camera/rcar_vin.c
@@ -513,7 +513,7 @@ static int rcar_vin_videobuf_init(struct vb2_buffer *vb)
return 0;
}
-static int rcar_vin_stop_streaming(struct vb2_queue *vq)
+static void rcar_vin_stop_streaming(struct vb2_queue *vq)
{
struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -524,8 +524,6 @@ static int rcar_vin_stop_streaming(struct vb2_queue *vq)
list_for_each_safe(buf_head, tmp, &priv->capture)
list_del_init(buf_head);
spin_unlock_irq(&priv->lock);
-
- return 0;
}
static struct vb2_ops rcar_vin_vb2_ops = {
diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
index 3e75a469cd49..20ad4a571d37 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
@@ -471,7 +471,7 @@ static int sh_mobile_ceu_videobuf_init(struct vb2_buffer *vb)
return 0;
}
-static int sh_mobile_ceu_stop_streaming(struct vb2_queue *q)
+static void sh_mobile_ceu_stop_streaming(struct vb2_queue *q)
{
struct soc_camera_device *icd = container_of(q, struct soc_camera_device, vb2_vidq);
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
@@ -487,7 +487,7 @@ static int sh_mobile_ceu_stop_streaming(struct vb2_queue *q)
spin_unlock_irq(&pcdev->lock);
- return sh_mobile_ceu_soft_reset(pcdev);
+ sh_mobile_ceu_soft_reset(pcdev);
}
static struct vb2_ops sh_mobile_ceu_videobuf_ops = {
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index 4b8c024fc487..7fec8cdaf095 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -314,7 +314,7 @@ static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id a)
struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- return v4l2_subdev_call(sd, core, s_std, a);
+ return v4l2_subdev_call(sd, video, s_std, a);
}
static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a)
@@ -322,7 +322,7 @@ static int soc_camera_g_std(struct file *file, void *priv, v4l2_std_id *a)
struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- return v4l2_subdev_call(sd, core, g_std, a);
+ return v4l2_subdev_call(sd, video, g_std, a);
}
static int soc_camera_enum_framesizes(struct file *file, void *fh,
@@ -1277,6 +1277,8 @@ static int soc_camera_probe_finish(struct soc_camera_device *icd)
sd->grp_id = soc_camera_grp_id(icd);
v4l2_set_subdev_hostdata(sd, icd);
+ v4l2_subdev_call(sd, video, g_tvnorms, &icd->vdev->tvnorms);
+
ret = v4l2_ctrl_add_handler(&icd->ctrl_handler, sd->ctrl_handler, NULL);
if (ret < 0)
return ret;
@@ -1997,6 +1999,12 @@ static int soc_camera_video_start(struct soc_camera_device *icd)
return -ENODEV;
video_set_drvdata(icd->vdev, icd);
+ if (icd->vdev->tvnorms == 0) {
+ /* disable the STD API if there are no tvnorms defined */
+ v4l2_disable_ioctl(icd->vdev, VIDIOC_G_STD);
+ v4l2_disable_ioctl(icd->vdev, VIDIOC_S_STD);
+ v4l2_disable_ioctl(icd->vdev, VIDIOC_ENUMSTD);
+ }
ret = video_register_device(icd->vdev, VFL_TYPE_GRABBER, -1);
if (ret < 0) {
dev_err(icd->pdev, "video_register_device failed: %d\n", ret);
diff --git a/drivers/media/platform/ti-vpe/csc.c b/drivers/media/platform/ti-vpe/csc.c
index acfea500710e..940df4000c42 100644
--- a/drivers/media/platform/ti-vpe/csc.c
+++ b/drivers/media/platform/ti-vpe/csc.c
@@ -180,16 +180,16 @@ struct csc_data *csc_create(struct platform_device *pdev)
csc->pdev = pdev;
csc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
- "vpe_csc");
+ "csc");
if (csc->res == NULL) {
dev_err(&pdev->dev, "missing platform resources data\n");
return ERR_PTR(-ENODEV);
}
csc->base = devm_ioremap_resource(&pdev->dev, csc->res);
- if (!csc->base) {
+ if (IS_ERR(csc->base)) {
dev_err(&pdev->dev, "failed to ioremap\n");
- return ERR_PTR(-ENOMEM);
+ return csc->base;
}
return csc;
diff --git a/drivers/media/platform/ti-vpe/sc.c b/drivers/media/platform/ti-vpe/sc.c
index 93f0af546b76..6314171ffe9b 100644
--- a/drivers/media/platform/ti-vpe/sc.c
+++ b/drivers/media/platform/ti-vpe/sc.c
@@ -302,9 +302,9 @@ struct sc_data *sc_create(struct platform_device *pdev)
}
sc->base = devm_ioremap_resource(&pdev->dev, sc->res);
- if (!sc->base) {
+ if (IS_ERR(sc->base)) {
dev_err(&pdev->dev, "failed to ioremap\n");
- return ERR_PTR(-ENOMEM);
+ return sc->base;
}
return sc;
diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c
index e8175e7938ed..a51a01359805 100644
--- a/drivers/media/platform/ti-vpe/vpdma.c
+++ b/drivers/media/platform/ti-vpe/vpdma.c
@@ -614,8 +614,17 @@ static void dump_dtd(struct vpdma_dtd *dtd)
/*
* append an outbound data transfer descriptor to the given descriptor list,
* this sets up a 'client to memory' VPDMA transfer for the given VPDMA channel
+ *
+ * @list: vpdma desc list to which we add this decriptor
+ * @width: width of the image in pixels in memory
+ * @c_rect: compose params of output image
+ * @fmt: vpdma data format of the buffer
+ * dma_addr: dma address as seen by VPDMA
+ * chan: VPDMA channel
+ * flags: VPDMA flags to configure some descriptor fileds
*/
-void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
+void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width,
+ const struct v4l2_rect *c_rect,
const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
enum vpdma_channel chan, u32 flags)
{
@@ -623,6 +632,7 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
int field = 0;
int notify = 1;
int channel, next_chan;
+ struct v4l2_rect rect = *c_rect;
int depth = fmt->depth;
int stride;
struct vpdma_dtd *dtd;
@@ -630,11 +640,15 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
channel = next_chan = chan_info[chan].num;
if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV &&
- fmt->data_type == DATA_TYPE_C420)
+ fmt->data_type == DATA_TYPE_C420) {
+ rect.height >>= 1;
+ rect.top >>= 1;
depth = 8;
+ }
- stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN);
- dma_addr += (c_rect->left * depth) >> 3;
+ stride = ALIGN((depth * width) >> 3, VPDMA_STRIDE_ALIGN);
+
+ dma_addr += rect.top * stride + (rect.left * depth >> 3);
dtd = list->next;
WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size));
@@ -664,31 +678,48 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
/*
* append an inbound data transfer descriptor to the given descriptor list,
* this sets up a 'memory to client' VPDMA transfer for the given VPDMA channel
+ *
+ * @list: vpdma desc list to which we add this decriptor
+ * @width: width of the image in pixels in memory(not the cropped width)
+ * @c_rect: crop params of input image
+ * @fmt: vpdma data format of the buffer
+ * dma_addr: dma address as seen by VPDMA
+ * chan: VPDMA channel
+ * field: top or bottom field info of the input image
+ * flags: VPDMA flags to configure some descriptor fileds
+ * frame_width/height: the complete width/height of the image presented to the
+ * client (this makes sense when multiple channels are
+ * connected to the same client, forming a larger frame)
+ * start_h, start_v: position where the given channel starts providing pixel
+ * data to the client (makes sense when multiple channels
+ * contribute to the client)
*/
-void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
- int frame_height, struct v4l2_rect *c_rect,
+void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
+ const struct v4l2_rect *c_rect,
const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
- enum vpdma_channel chan, int field, u32 flags)
+ enum vpdma_channel chan, int field, u32 flags, int frame_width,
+ int frame_height, int start_h, int start_v)
{
int priority = 0;
int notify = 1;
int depth = fmt->depth;
int channel, next_chan;
+ struct v4l2_rect rect = *c_rect;
int stride;
- int height = c_rect->height;
struct vpdma_dtd *dtd;
channel = next_chan = chan_info[chan].num;
if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV &&
fmt->data_type == DATA_TYPE_C420) {
- height >>= 1;
- frame_height >>= 1;
+ rect.height >>= 1;
+ rect.top >>= 1;
depth = 8;
}
- stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN);
- dma_addr += (c_rect->left * depth) >> 3;
+ stride = ALIGN((depth * width) >> 3, VPDMA_STRIDE_ALIGN);
+
+ dma_addr += rect.top * stride + (rect.left * depth >> 3);
dtd = list->next;
WARN_ON((void *)(dtd + 1) > (list->buf.addr + list->buf.size));
@@ -701,13 +732,14 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
!!(flags & VPDMA_DATA_ODD_LINE_SKIP),
stride);
- dtd->xfer_length_height = dtd_xfer_length_height(c_rect->width, height);
+ dtd->xfer_length_height = dtd_xfer_length_height(rect.width,
+ rect.height);
dtd->start_addr = (u32) dma_addr;
dtd->pkt_ctl = dtd_pkt_ctl(!!(flags & VPDMA_DATA_MODE_TILED),
DTD_DIR_IN, channel, priority, next_chan);
dtd->frame_width_height = dtd_frame_width_height(frame_width,
frame_height);
- dtd->start_h_v = dtd_start_h_v(c_rect->left, c_rect->top);
+ dtd->start_h_v = dtd_start_h_v(start_h, start_v);
dtd->client_attr0 = 0;
dtd->client_attr1 = 0;
@@ -781,7 +813,7 @@ static void vpdma_firmware_cb(const struct firmware *f, void *context)
/* already initialized */
if (read_field_reg(vpdma, VPDMA_LIST_ATTR, VPDMA_LIST_RDY_MASK,
VPDMA_LIST_RDY_SHFT)) {
- vpdma->ready = true;
+ vpdma->cb(vpdma->pdev);
return;
}
@@ -811,7 +843,7 @@ static void vpdma_firmware_cb(const struct firmware *f, void *context)
goto free_buf;
}
- vpdma->ready = true;
+ vpdma->cb(vpdma->pdev);
free_buf:
vpdma_unmap_desc_buf(vpdma, &fw_dma_buf);
@@ -839,7 +871,8 @@ static int vpdma_load_firmware(struct vpdma_data *vpdma)
return 0;
}
-struct vpdma_data *vpdma_create(struct platform_device *pdev)
+struct vpdma_data *vpdma_create(struct platform_device *pdev,
+ void (*cb)(struct platform_device *pdev))
{
struct resource *res;
struct vpdma_data *vpdma;
@@ -854,6 +887,7 @@ struct vpdma_data *vpdma_create(struct platform_device *pdev)
}
vpdma->pdev = pdev;
+ vpdma->cb = cb;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpdma");
if (res == NULL) {
diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h
index cf40f11b3c8f..2bd8fb050381 100644
--- a/drivers/media/platform/ti-vpe/vpdma.h
+++ b/drivers/media/platform/ti-vpe/vpdma.h
@@ -35,8 +35,8 @@ struct vpdma_data {
struct platform_device *pdev;
- /* tells whether vpdma firmware is loaded or not */
- bool ready;
+ /* callback to VPE driver when the firmware is loaded */
+ void (*cb)(struct platform_device *pdev);
};
enum vpdma_data_format_type {
@@ -186,13 +186,15 @@ void vpdma_add_cfd_adb(struct vpdma_desc_list *list, int client,
struct vpdma_buf *adb);
void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list,
enum vpdma_channel chan);
-void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
+void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width,
+ const struct v4l2_rect *c_rect,
const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
enum vpdma_channel chan, u32 flags);
-void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
- int frame_height, struct v4l2_rect *c_rect,
+void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width,
+ const struct v4l2_rect *c_rect,
const struct vpdma_data_format *fmt, dma_addr_t dma_addr,
- enum vpdma_channel chan, int field, u32 flags);
+ enum vpdma_channel chan, int field, u32 flags, int frame_width,
+ int frame_height, int start_h, int start_v);
/* vpdma list interrupt management */
void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int list_num,
@@ -208,6 +210,7 @@ void vpdma_set_frame_start_event(struct vpdma_data *vpdma,
void vpdma_dump_regs(struct vpdma_data *vpdma);
/* initialize vpdma, passed with VPE's platform device pointer */
-struct vpdma_data *vpdma_create(struct platform_device *pdev);
+struct vpdma_data *vpdma_create(struct platform_device *pdev,
+ void (*cb)(struct platform_device *pdev));
#endif
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c
index 5c421886d97c..972f43f69206 100644
--- a/drivers/media/platform/ti-vpe/vpe.c
+++ b/drivers/media/platform/ti-vpe/vpe.c
@@ -410,8 +410,10 @@ static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx,
{
switch (type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return &ctx->q_data[Q_DATA_SRC];
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
return &ctx->q_data[Q_DATA_DST];
default:
BUG();
@@ -986,7 +988,6 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_DST];
const struct vpe_port_data *p_data = &port_data[port];
struct vb2_buffer *vb = ctx->dst_vb;
- struct v4l2_rect *c_rect = &q_data->c_rect;
struct vpe_fmt *fmt = q_data->fmt;
const struct vpdma_data_format *vpdma_fmt;
int mv_buf_selector = !ctx->src_mv_buf_selector;
@@ -1015,8 +1016,8 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port)
if (q_data->flags & Q_DATA_MODE_TILED)
flags |= VPDMA_DATA_MODE_TILED;
- vpdma_add_out_dtd(&ctx->desc_list, c_rect, vpdma_fmt, dma_addr,
- p_data->channel, flags);
+ vpdma_add_out_dtd(&ctx->desc_list, q_data->width, &q_data->c_rect,
+ vpdma_fmt, dma_addr, p_data->channel, flags);
}
static void add_in_dtd(struct vpe_ctx *ctx, int port)
@@ -1024,11 +1025,11 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
struct vpe_q_data *q_data = &ctx->q_data[Q_DATA_SRC];
const struct vpe_port_data *p_data = &port_data[port];
struct vb2_buffer *vb = ctx->src_vbs[p_data->vb_index];
- struct v4l2_rect *c_rect = &q_data->c_rect;
struct vpe_fmt *fmt = q_data->fmt;
const struct vpdma_data_format *vpdma_fmt;
int mv_buf_selector = ctx->src_mv_buf_selector;
int field = vb->v4l2_buf.field == V4L2_FIELD_BOTTOM;
+ int frame_width, frame_height;
dma_addr_t dma_addr;
u32 flags = 0;
@@ -1055,8 +1056,15 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port)
if (q_data->flags & Q_DATA_MODE_TILED)
flags |= VPDMA_DATA_MODE_TILED;
- vpdma_add_in_dtd(&ctx->desc_list, q_data->width, q_data->height,
- c_rect, vpdma_fmt, dma_addr, p_data->channel, field, flags);
+ frame_width = q_data->c_rect.width;
+ frame_height = q_data->c_rect.height;
+
+ if (p_data->vb_part && fmt->fourcc == V4L2_PIX_FMT_NV12)
+ frame_height /= 2;
+
+ vpdma_add_in_dtd(&ctx->desc_list, q_data->width, &q_data->c_rect,
+ vpdma_fmt, dma_addr, p_data->channel, field, flags, frame_width,
+ frame_height, 0, 0);
}
/*
@@ -1585,6 +1593,151 @@ static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
return set_srcdst_params(ctx);
}
+static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s)
+{
+ struct vpe_q_data *q_data;
+
+ if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+ return -EINVAL;
+
+ q_data = get_q_data(ctx, s->type);
+ if (!q_data)
+ return -EINVAL;
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE:
+ /*
+ * COMPOSE target is only valid for capture buffer type, return
+ * error for output buffer type
+ */
+ if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+ break;
+ case V4L2_SEL_TGT_CROP:
+ /*
+ * CROP target is only valid for output buffer type, return
+ * error for capture buffer type
+ */
+ if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ break;
+ /*
+ * bound and default crop/compose targets are invalid targets to
+ * try/set
+ */
+ default:
+ return -EINVAL;
+ }
+
+ if (s->r.top < 0 || s->r.left < 0) {
+ vpe_err(ctx->dev, "negative values for top and left\n");
+ s->r.top = s->r.left = 0;
+ }
+
+ v4l_bound_align_image(&s->r.width, MIN_W, q_data->width, 1,
+ &s->r.height, MIN_H, q_data->height, H_ALIGN, S_ALIGN);
+
+ /* adjust left/top if cropping rectangle is out of bounds */
+ if (s->r.left + s->r.width > q_data->width)
+ s->r.left = q_data->width - s->r.width;
+ if (s->r.top + s->r.height > q_data->height)
+ s->r.top = q_data->height - s->r.height;
+
+ return 0;
+}
+
+static int vpe_g_selection(struct file *file, void *fh,
+ struct v4l2_selection *s)
+{
+ struct vpe_ctx *ctx = file2ctx(file);
+ struct vpe_q_data *q_data;
+ bool use_c_rect = false;
+
+ if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
+ (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT))
+ return -EINVAL;
+
+ q_data = get_q_data(ctx, s->type);
+ if (!q_data)
+ return -EINVAL;
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+ break;
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ break;
+ case V4L2_SEL_TGT_COMPOSE:
+ if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+ use_c_rect = true;
+ break;
+ case V4L2_SEL_TGT_CROP:
+ if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ use_c_rect = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (use_c_rect) {
+ /*
+ * for CROP/COMPOSE target type, return c_rect params from the
+ * respective buffer type
+ */
+ s->r = q_data->c_rect;
+ } else {
+ /*
+ * for DEFAULT/BOUNDS target type, return width and height from
+ * S_FMT of the respective buffer type
+ */
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = q_data->width;
+ s->r.height = q_data->height;
+ }
+
+ return 0;
+}
+
+
+static int vpe_s_selection(struct file *file, void *fh,
+ struct v4l2_selection *s)
+{
+ struct vpe_ctx *ctx = file2ctx(file);
+ struct vpe_q_data *q_data;
+ struct v4l2_selection sel = *s;
+ int ret;
+
+ ret = __vpe_try_selection(ctx, &sel);
+ if (ret)
+ return ret;
+
+ q_data = get_q_data(ctx, sel.type);
+ if (!q_data)
+ return -EINVAL;
+
+ if ((q_data->c_rect.left == sel.r.left) &&
+ (q_data->c_rect.top == sel.r.top) &&
+ (q_data->c_rect.width == sel.r.width) &&
+ (q_data->c_rect.height == sel.r.height)) {
+ vpe_dbg(ctx->dev,
+ "requested crop/compose values are already set\n");
+ return 0;
+ }
+
+ q_data->c_rect = sel.r;
+
+ return set_srcdst_params(ctx);
+}
+
static int vpe_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *reqbufs)
{
@@ -1672,6 +1825,9 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = {
.vidioc_try_fmt_vid_out_mplane = vpe_try_fmt,
.vidioc_s_fmt_vid_out_mplane = vpe_s_fmt,
+ .vidioc_g_selection = vpe_g_selection,
+ .vidioc_s_selection = vpe_s_selection,
+
.vidioc_reqbufs = vpe_reqbufs,
.vidioc_querybuf = vpe_querybuf,
@@ -1784,7 +1940,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
memset(src_vq, 0, sizeof(*src_vq));
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
- src_vq->io_modes = VB2_MMAP;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
src_vq->drv_priv = ctx;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &vpe_qops;
@@ -1797,7 +1953,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
memset(dst_vq, 0, sizeof(*dst_vq));
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
- dst_vq->io_modes = VB2_MMAP;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
dst_vq->drv_priv = ctx;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &vpe_qops;
@@ -1831,11 +1987,6 @@ static int vpe_open(struct file *file)
vpe_dbg(dev, "vpe_open\n");
- if (!dev->vpdma->ready) {
- vpe_err(dev, "vpdma firmware not loaded\n");
- return -ENODEV;
- }
-
ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return -ENOMEM;
@@ -2055,10 +2206,40 @@ static void vpe_runtime_put(struct platform_device *pdev)
WARN_ON(r < 0 && r != -ENOSYS);
}
+static void vpe_fw_cb(struct platform_device *pdev)
+{
+ struct vpe_dev *dev = platform_get_drvdata(pdev);
+ struct video_device *vfd;
+ int ret;
+
+ vfd = &dev->vfd;
+ *vfd = vpe_videodev;
+ vfd->lock = &dev->dev_mutex;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
+ if (ret) {
+ vpe_err(dev, "Failed to register video device\n");
+
+ vpe_set_clock_enable(dev, 0);
+ vpe_runtime_put(pdev);
+ pm_runtime_disable(&pdev->dev);
+ v4l2_m2m_release(dev->m2m_dev);
+ vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
+ v4l2_device_unregister(&dev->v4l2_dev);
+
+ return;
+ }
+
+ video_set_drvdata(vfd, dev);
+ snprintf(vfd->name, sizeof(vfd->name), "%s", vpe_videodev.name);
+ dev_info(dev->v4l2_dev.dev, "Device registered as /dev/video%d\n",
+ vfd->num);
+}
+
static int vpe_probe(struct platform_device *pdev)
{
struct vpe_dev *dev;
- struct video_device *vfd;
int ret, irq, func;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
@@ -2139,28 +2320,12 @@ static int vpe_probe(struct platform_device *pdev)
goto runtime_put;
}
- dev->vpdma = vpdma_create(pdev);
+ dev->vpdma = vpdma_create(pdev, vpe_fw_cb);
if (IS_ERR(dev->vpdma)) {
ret = PTR_ERR(dev->vpdma);
goto runtime_put;
}
- vfd = &dev->vfd;
- *vfd = vpe_videodev;
- vfd->lock = &dev->dev_mutex;
- vfd->v4l2_dev = &dev->v4l2_dev;
-
- ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
- if (ret) {
- vpe_err(dev, "Failed to register video device\n");
- goto runtime_put;
- }
-
- video_set_drvdata(vfd, dev);
- snprintf(vfd->name, sizeof(vfd->name), "%s", vpe_videodev.name);
- dev_info(dev->v4l2_dev.dev, "Device registered as /dev/video%d\n",
- vfd->num);
-
return 0;
runtime_put:
diff --git a/drivers/media/platform/timblogiw.c b/drivers/media/platform/timblogiw.c
index ccdadd623a3a..3cb2f3564873 100644
--- a/drivers/media/platform/timblogiw.c
+++ b/drivers/media/platform/timblogiw.c
@@ -347,7 +347,7 @@ static int timblogiw_s_std(struct file *file, void *priv, v4l2_std_id std)
mutex_lock(&lw->lock);
if (TIMBLOGIW_HAS_DECODER(lw))
- err = v4l2_subdev_call(lw->sd_enc, core, s_std, std);
+ err = v4l2_subdev_call(lw->sd_enc, video, s_std, std);
if (!err)
fh->cur_norm = timblogiw_get_norm(std);
@@ -800,7 +800,7 @@ static int timblogiw_probe(struct platform_device *pdev)
if (!pdata->encoder.module_name)
dev_info(&pdev->dev, "Running without decoder\n");
- lw = kzalloc(sizeof(*lw), GFP_KERNEL);
+ lw = devm_kzalloc(&pdev->dev, sizeof(*lw), GFP_KERNEL);
if (!lw) {
err = -ENOMEM;
goto err;
@@ -820,7 +820,7 @@ static int timblogiw_probe(struct platform_device *pdev)
strlcpy(lw->v4l2_dev.name, DRIVER_NAME, sizeof(lw->v4l2_dev.name));
err = v4l2_device_register(NULL, &lw->v4l2_dev);
if (err)
- goto err_register;
+ goto err;
lw->video_dev.v4l2_dev = &lw->v4l2_dev;
@@ -837,8 +837,6 @@ static int timblogiw_probe(struct platform_device *pdev)
err_request:
v4l2_device_unregister(&lw->v4l2_dev);
-err_register:
- kfree(lw);
err:
dev_err(&pdev->dev, "Failed to register: %d\n", err);
@@ -853,8 +851,6 @@ static int timblogiw_remove(struct platform_device *pdev)
v4l2_device_unregister(&lw->v4l2_dev);
- kfree(lw);
-
return 0;
}
diff --git a/drivers/media/platform/vino.c b/drivers/media/platform/vino.c
index c6af974c5b45..470d35336119 100644
--- a/drivers/media/platform/vino.c
+++ b/drivers/media/platform/vino.c
@@ -2586,7 +2586,7 @@ static int vino_acquire_input(struct vino_channel_settings *vcs)
}
if (data_norm == 3)
data_norm = VINO_DATA_NORM_PAL;
- ret = decoder_call(core, s_std, norm);
+ ret = decoder_call(video, s_std, norm);
}
spin_lock_irqsave(&vino_drvdata->input_lock, flags);
@@ -2675,7 +2675,7 @@ static int vino_set_input(struct vino_channel_settings *vcs, int input)
}
if (data_norm == 3)
data_norm = VINO_DATA_NORM_PAL;
- ret = decoder_call(core, s_std, norm);
+ ret = decoder_call(video, s_std, norm);
}
spin_lock_irqsave(&vino_drvdata->input_lock, flags);
@@ -2809,7 +2809,7 @@ static int vino_set_data_norm(struct vino_channel_settings *vcs,
* as it may take a while... */
norm = vino_data_norms[data_norm].std;
- err = decoder_call(core, s_std, norm);
+ err = decoder_call(video, s_std, norm);
spin_lock_irqsave(&vino_drvdata->input_lock, *flags);
diff --git a/drivers/media/platform/vivi.c b/drivers/media/platform/vivi.c
index 3890f4f42a78..d00bf3df0f8a 100644
--- a/drivers/media/platform/vivi.c
+++ b/drivers/media/platform/vivi.c
@@ -906,12 +906,11 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
}
/* abort streaming and wait for last buffer */
-static int stop_streaming(struct vb2_queue *vq)
+static void stop_streaming(struct vb2_queue *vq)
{
struct vivi_dev *dev = vb2_get_drv_priv(vq);
dprintk(dev, 1, "%s\n", __func__);
vivi_stop_generating(dev);
- return 0;
}
static void vivi_lock(struct vb2_queue *vq)
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index b48f135ffc01..a0595c17700f 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -720,7 +720,7 @@ static int vsp1_video_start_streaming(struct vb2_queue *vq, unsigned int count)
return 0;
}
-static int vsp1_video_stop_streaming(struct vb2_queue *vq)
+static void vsp1_video_stop_streaming(struct vb2_queue *vq)
{
struct vsp1_video *video = vb2_get_drv_priv(vq);
struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
@@ -743,8 +743,6 @@ static int vsp1_video_stop_streaming(struct vb2_queue *vq)
spin_lock_irqsave(&video->irqlock, flags);
INIT_LIST_HEAD(&video->irqqueue);
spin_unlock_irqrestore(&video->irqlock, flags);
-
- return 0;
}
static struct vb2_ops vsp1_video_queue_qops = {
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 5d8f3d40d820..d5c1df3c9db1 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -747,11 +747,19 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data,
}
/* outbound data */
- pipe = usb_sndintpipe(ir->usbdev,
- ir->usb_ep_out->bEndpointAddress);
- usb_fill_int_urb(async_urb, ir->usbdev, pipe,
- async_buf, size, mce_async_callback,
- ir, ir->usb_ep_out->bInterval);
+ if (usb_endpoint_xfer_int(ir->usb_ep_out)) {
+ pipe = usb_sndintpipe(ir->usbdev,
+ ir->usb_ep_out->bEndpointAddress);
+ usb_fill_int_urb(async_urb, ir->usbdev, pipe, async_buf,
+ size, mce_async_callback, ir,
+ ir->usb_ep_out->bInterval);
+ } else {
+ pipe = usb_sndbulkpipe(ir->usbdev,
+ ir->usb_ep_out->bEndpointAddress);
+ usb_fill_bulk_urb(async_urb, ir->usbdev, pipe,
+ async_buf, size, mce_async_callback,
+ ir);
+ }
memcpy(async_buf, data, size);
} else if (urb_type == MCEUSB_RX) {
@@ -1269,32 +1277,26 @@ static int mceusb_dev_probe(struct usb_interface *intf,
for (i = 0; i < idesc->desc.bNumEndpoints; ++i) {
ep = &idesc->endpoint[i].desc;
- if ((ep_in == NULL)
- && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- == USB_DIR_IN)
- && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK)
- || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_INT))) {
-
- ep_in = ep;
- ep_in->bmAttributes = USB_ENDPOINT_XFER_INT;
- ep_in->bInterval = 1;
- dev_dbg(&intf->dev, "acceptable inbound endpoint found");
+ if (ep_in == NULL) {
+ if (usb_endpoint_is_bulk_in(ep)) {
+ ep_in = ep;
+ dev_dbg(&intf->dev, "acceptable bulk inbound endpoint found\n");
+ } else if (usb_endpoint_is_int_in(ep)) {
+ ep_in = ep;
+ ep_in->bInterval = 1;
+ dev_dbg(&intf->dev, "acceptable interrupt inbound endpoint found\n");
+ }
}
- if ((ep_out == NULL)
- && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- == USB_DIR_OUT)
- && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_BULK)
- || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- == USB_ENDPOINT_XFER_INT))) {
-
- ep_out = ep;
- ep_out->bmAttributes = USB_ENDPOINT_XFER_INT;
- ep_out->bInterval = 1;
- dev_dbg(&intf->dev, "acceptable outbound endpoint found");
+ if (ep_out == NULL) {
+ if (usb_endpoint_is_bulk_out(ep)) {
+ ep_out = ep;
+ dev_dbg(&intf->dev, "acceptable bulk outbound endpoint found\n");
+ } else if (usb_endpoint_is_int_out(ep)) {
+ ep_out = ep;
+ ep_out->bInterval = 1;
+ dev_dbg(&intf->dev, "acceptable interrupt outbound endpoint found\n");
+ }
}
}
if (ep_in == NULL) {
@@ -1302,7 +1304,10 @@ static int mceusb_dev_probe(struct usb_interface *intf,
return -ENODEV;
}
- pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress);
+ if (usb_endpoint_xfer_int(ep_in))
+ pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress);
+ else
+ pipe = usb_rcvbulkpipe(dev, ep_in->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
ir = kzalloc(sizeof(struct mceusb_dev), GFP_KERNEL);
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
index a1284889cd15..22b6b8bb1d93 100644
--- a/drivers/media/tuners/Kconfig
+++ b/drivers/media/tuners/Kconfig
@@ -230,6 +230,13 @@ config MEDIA_TUNER_TUA9001
help
Infineon TUA 9001 silicon tuner driver.
+config MEDIA_TUNER_SI2157
+ tristate "Silicon Labs Si2157 silicon tuner"
+ depends on MEDIA_SUPPORT && I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Silicon Labs Si2157 silicon tuner driver.
+
config MEDIA_TUNER_IT913X
tristate "ITE Tech IT913x silicon tuner"
depends on MEDIA_SUPPORT && I2C
diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile
index efe82a904b12..a6ff0c628dfa 100644
--- a/drivers/media/tuners/Makefile
+++ b/drivers/media/tuners/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
obj-$(CONFIG_MEDIA_TUNER_E4000) += e4000.o
obj-$(CONFIG_MEDIA_TUNER_FC2580) += fc2580.o
obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o
+obj-$(CONFIG_MEDIA_TUNER_SI2157) += si2157.o
obj-$(CONFIG_MEDIA_TUNER_M88TS2022) += m88ts2022.o
obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
new file mode 100644
index 000000000000..271a752cee54
--- /dev/null
+++ b/drivers/media/tuners/si2157.c
@@ -0,0 +1,260 @@
+/*
+ * Silicon Labs Si2157 silicon tuner driver
+ *
+ * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "si2157_priv.h"
+
+/* execute firmware command */
+static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd)
+{
+ int ret;
+ u8 buf[1];
+ unsigned long timeout;
+
+ mutex_lock(&s->i2c_mutex);
+
+ if (cmd->len) {
+ /* write cmd and args for firmware */
+ ret = i2c_master_send(s->client, cmd->args, cmd->len);
+ if (ret < 0) {
+ goto err_mutex_unlock;
+ } else if (ret != cmd->len) {
+ ret = -EREMOTEIO;
+ goto err_mutex_unlock;
+ }
+ }
+
+ /* wait cmd execution terminate */
+ #define TIMEOUT 80
+ timeout = jiffies + msecs_to_jiffies(TIMEOUT);
+ while (!time_after(jiffies, timeout)) {
+ ret = i2c_master_recv(s->client, buf, 1);
+ if (ret < 0) {
+ goto err_mutex_unlock;
+ } else if (ret != 1) {
+ ret = -EREMOTEIO;
+ goto err_mutex_unlock;
+ }
+
+ /* firmware ready? */
+ if ((buf[0] >> 7) & 0x01)
+ break;
+ }
+
+ dev_dbg(&s->client->dev, "%s: cmd execution took %d ms\n", __func__,
+ jiffies_to_msecs(jiffies) -
+ (jiffies_to_msecs(timeout) - TIMEOUT));
+
+ if (!(buf[0] >> 7) & 0x01) {
+ ret = -ETIMEDOUT;
+ goto err_mutex_unlock;
+ } else {
+ ret = 0;
+ }
+
+err_mutex_unlock:
+ mutex_unlock(&s->i2c_mutex);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static int si2157_init(struct dvb_frontend *fe)
+{
+ struct si2157 *s = fe->tuner_priv;
+
+ dev_dbg(&s->client->dev, "%s:\n", __func__);
+
+ s->active = true;
+
+ return 0;
+}
+
+static int si2157_sleep(struct dvb_frontend *fe)
+{
+ struct si2157 *s = fe->tuner_priv;
+
+ dev_dbg(&s->client->dev, "%s:\n", __func__);
+
+ s->active = false;
+
+ return 0;
+}
+
+static int si2157_set_params(struct dvb_frontend *fe)
+{
+ struct si2157 *s = fe->tuner_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ struct si2157_cmd cmd;
+
+ dev_dbg(&s->client->dev,
+ "%s: delivery_system=%d frequency=%u bandwidth_hz=%u\n",
+ __func__, c->delivery_system, c->frequency,
+ c->bandwidth_hz);
+
+ if (!s->active) {
+ ret = -EAGAIN;
+ goto err;
+ }
+
+ /* configure? */
+ cmd.args[0] = 0xc0;
+ cmd.args[1] = 0x00;
+ cmd.args[2] = 0x0c;
+ cmd.args[3] = 0x00;
+ cmd.args[4] = 0x00;
+ cmd.args[5] = 0x01;
+ cmd.args[6] = 0x01;
+ cmd.args[7] = 0x01;
+ cmd.args[8] = 0x01;
+ cmd.args[9] = 0x01;
+ cmd.args[10] = 0x01;
+ cmd.args[11] = 0x02;
+ cmd.args[12] = 0x00;
+ cmd.args[13] = 0x00;
+ cmd.args[14] = 0x01;
+ cmd.len = 15;
+ ret = si2157_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ cmd.args[0] = 0x02;
+ cmd.len = 1;
+ ret = si2157_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ cmd.args[0] = 0x01;
+ cmd.args[1] = 0x01;
+ cmd.len = 2;
+ ret = si2157_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ /* set frequency */
+ cmd.args[0] = 0x41;
+ cmd.args[1] = 0x00;
+ cmd.args[2] = 0x00;
+ cmd.args[3] = 0x00;
+ cmd.args[4] = (c->frequency >> 0) & 0xff;
+ cmd.args[5] = (c->frequency >> 8) & 0xff;
+ cmd.args[6] = (c->frequency >> 16) & 0xff;
+ cmd.args[7] = (c->frequency >> 24) & 0xff;
+ cmd.len = 8;
+ ret = si2157_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ dev_dbg(&s->client->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
+static const struct dvb_tuner_ops si2157_tuner_ops = {
+ .info = {
+ .name = "Silicon Labs Si2157",
+ .frequency_min = 110000000,
+ .frequency_max = 862000000,
+ },
+
+ .init = si2157_init,
+ .sleep = si2157_sleep,
+ .set_params = si2157_set_params,
+};
+
+static int si2157_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct si2157_config *cfg = client->dev.platform_data;
+ struct dvb_frontend *fe = cfg->fe;
+ struct si2157 *s;
+ struct si2157_cmd cmd;
+ int ret;
+
+ s = kzalloc(sizeof(struct si2157), GFP_KERNEL);
+ if (!s) {
+ ret = -ENOMEM;
+ dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+ goto err;
+ }
+
+ s->client = client;
+ s->fe = cfg->fe;
+ mutex_init(&s->i2c_mutex);
+
+ /* check if the tuner is there */
+ cmd.len = 0;
+ ret = si2157_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ fe->tuner_priv = s;
+ memcpy(&fe->ops.tuner_ops, &si2157_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ i2c_set_clientdata(client, s);
+
+ dev_info(&s->client->dev,
+ "%s: Silicon Labs Si2157 successfully attached\n",
+ KBUILD_MODNAME);
+ return 0;
+err:
+ dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
+ kfree(s);
+
+ return ret;
+}
+
+static int si2157_remove(struct i2c_client *client)
+{
+ struct si2157 *s = i2c_get_clientdata(client);
+ struct dvb_frontend *fe = s->fe;
+
+ dev_dbg(&client->dev, "%s:\n", __func__);
+
+ memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
+ fe->tuner_priv = NULL;
+ kfree(s);
+
+ return 0;
+}
+
+static const struct i2c_device_id si2157_id[] = {
+ {"si2157", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, si2157_id);
+
+static struct i2c_driver si2157_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "si2157",
+ },
+ .probe = si2157_probe,
+ .remove = si2157_remove,
+ .id_table = si2157_id,
+};
+
+module_i2c_driver(si2157_driver);
+
+MODULE_DESCRIPTION("Silicon Labs Si2157 silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h
new file mode 100644
index 000000000000..f469a092b66b
--- /dev/null
+++ b/drivers/media/tuners/si2157.h
@@ -0,0 +1,34 @@
+/*
+ * Silicon Labs Si2157 silicon tuner driver
+ *
+ * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SI2157_H
+#define SI2157_H
+
+#include <linux/kconfig.h>
+#include "dvb_frontend.h"
+
+/*
+ * I2C address
+ * 0x60
+ */
+struct si2157_config {
+ /*
+ * frontend
+ */
+ struct dvb_frontend *fe;
+};
+
+#endif
diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h
new file mode 100644
index 000000000000..6cc6c6fdab7a
--- /dev/null
+++ b/drivers/media/tuners/si2157_priv.h
@@ -0,0 +1,37 @@
+/*
+ * Silicon Labs Si2157 silicon tuner driver
+ *
+ * Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef SI2157_PRIV_H
+#define SI2157_PRIV_H
+
+#include "si2157.h"
+
+/* state struct */
+struct si2157 {
+ struct mutex i2c_mutex;
+ struct i2c_client *client;
+ struct dvb_frontend *fe;
+ bool active;
+};
+
+/* firmare command struct */
+#define SI2157_ARGLEN 30
+struct si2157_cmd {
+ u8 args[SI2157_ARGLEN];
+ unsigned len;
+};
+
+#endif
diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c
index 5cd09a681b6a..2b3d514be672 100644
--- a/drivers/media/tuners/xc5000.c
+++ b/drivers/media/tuners/xc5000.c
@@ -25,6 +25,7 @@
#include <linux/moduleparam.h>
#include <linux/videodev2.h>
#include <linux/delay.h>
+#include <linux/workqueue.h>
#include <linux/dvb/frontend.h>
#include <linux/i2c.h>
@@ -65,26 +66,25 @@ struct xc5000_priv {
u16 pll_register_no;
u8 init_status_supported;
u8 fw_checksum_supported;
+
+ struct dvb_frontend *fe;
+ struct delayed_work timer_sleep;
};
/* Misc Defines */
#define MAX_TV_STANDARD 24
#define XC_MAX_I2C_WRITE_LENGTH 64
+/* Time to suspend after the .sleep callback is called */
+#define XC5000_SLEEP_TIME 5000 /* ms */
+
/* Signal Types */
#define XC_RF_MODE_AIR 0
#define XC_RF_MODE_CABLE 1
-/* Result codes */
-#define XC_RESULT_SUCCESS 0
-#define XC_RESULT_RESET_FAILURE 1
-#define XC_RESULT_I2C_WRITE_FAILURE 2
-#define XC_RESULT_I2C_READ_FAILURE 3
-#define XC_RESULT_OUT_OF_RANGE 5
-
/* Product id */
#define XC_PRODUCT_ID_FW_NOT_LOADED 0x2000
-#define XC_PRODUCT_ID_FW_LOADED 0x1388
+#define XC_PRODUCT_ID_FW_LOADED 0x1388
/* Registers */
#define XREG_INIT 0x00
@@ -152,16 +152,16 @@ struct xc5000_priv {
*/
struct XC_TV_STANDARD {
- char *Name;
- u16 AudioMode;
- u16 VideoMode;
+ char *name;
+ u16 audio_mode;
+ u16 video_mode;
};
/* Tuner standards */
#define MN_NTSC_PAL_BTSC 0
#define MN_NTSC_PAL_A2 1
#define MN_NTSC_PAL_EIAJ 2
-#define MN_NTSC_PAL_Mono 3
+#define MN_NTSC_PAL_MONO 3
#define BG_PAL_A2 4
#define BG_PAL_NICAM 5
#define BG_PAL_MONO 6
@@ -171,19 +171,19 @@ struct XC_TV_STANDARD {
#define DK_PAL_NICAM 10
#define DK_PAL_MONO 11
#define DK_SECAM_A2DK1 12
-#define DK_SECAM_A2LDK3 13
-#define DK_SECAM_A2MONO 14
+#define DK_SECAM_A2LDK3 13
+#define DK_SECAM_A2MONO 14
#define L_SECAM_NICAM 15
#define LC_SECAM_NICAM 16
#define DTV6 17
#define DTV8 18
#define DTV7_8 19
#define DTV7 20
-#define FM_Radio_INPUT2 21
-#define FM_Radio_INPUT1 22
-#define FM_Radio_INPUT1_MONO 23
+#define FM_RADIO_INPUT2 21
+#define FM_RADIO_INPUT1 22
+#define FM_RADIO_INPUT1_MONO 23
-static struct XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
+static struct XC_TV_STANDARD xc5000_standard[MAX_TV_STANDARD] = {
{"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
{"M/N-NTSC/PAL-A2", 0x0600, 0x8020},
{"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
@@ -249,7 +249,7 @@ static inline const struct xc5000_fw_cfg *xc5000_assign_firmware(int chip_id)
static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force);
static int xc5000_is_firmware_loaded(struct dvb_frontend *fe);
static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val);
-static int xc5000_TunerReset(struct dvb_frontend *fe);
+static int xc5000_tuner_reset(struct dvb_frontend *fe);
static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
{
@@ -258,9 +258,9 @@ static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
if (i2c_transfer(priv->i2c_props.adap, &msg, 1) != 1) {
printk(KERN_ERR "xc5000: I2C write failed (len=%i)\n", len);
- return XC_RESULT_I2C_WRITE_FAILURE;
+ return -EREMOTEIO;
}
- return XC_RESULT_SUCCESS;
+ return 0;
}
#if 0
@@ -297,15 +297,10 @@ static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
}
*val = (bval[0] << 8) | bval[1];
- return XC_RESULT_SUCCESS;
-}
-
-static void xc_wait(int wait_ms)
-{
- msleep(wait_ms);
+ return 0;
}
-static int xc5000_TunerReset(struct dvb_frontend *fe)
+static int xc5000_tuner_reset(struct dvb_frontend *fe)
{
struct xc5000_priv *priv = fe->tuner_priv;
int ret;
@@ -320,43 +315,43 @@ static int xc5000_TunerReset(struct dvb_frontend *fe)
XC5000_TUNER_RESET, 0);
if (ret) {
printk(KERN_ERR "xc5000: reset failed\n");
- return XC_RESULT_RESET_FAILURE;
+ return ret;
}
} else {
printk(KERN_ERR "xc5000: no tuner reset callback function, fatal\n");
- return XC_RESULT_RESET_FAILURE;
+ return -EINVAL;
}
- return XC_RESULT_SUCCESS;
+ return 0;
}
-static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
+static int xc_write_reg(struct xc5000_priv *priv, u16 reg_addr, u16 i2c_data)
{
u8 buf[4];
- int WatchDogTimer = 100;
+ int watch_dog_timer = 100;
int result;
- buf[0] = (regAddr >> 8) & 0xFF;
- buf[1] = regAddr & 0xFF;
- buf[2] = (i2cData >> 8) & 0xFF;
- buf[3] = i2cData & 0xFF;
+ buf[0] = (reg_addr >> 8) & 0xFF;
+ buf[1] = reg_addr & 0xFF;
+ buf[2] = (i2c_data >> 8) & 0xFF;
+ buf[3] = i2c_data & 0xFF;
result = xc_send_i2c_data(priv, buf, 4);
- if (result == XC_RESULT_SUCCESS) {
+ if (result == 0) {
/* wait for busy flag to clear */
- while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) {
+ while ((watch_dog_timer > 0) && (result == 0)) {
result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf);
- if (result == XC_RESULT_SUCCESS) {
+ if (result == 0) {
if ((buf[0] == 0) && (buf[1] == 0)) {
/* busy flag cleared */
break;
} else {
- xc_wait(5); /* wait 5 ms */
- WatchDogTimer--;
+ msleep(5); /* wait 5 ms */
+ watch_dog_timer--;
}
}
}
}
- if (WatchDogTimer <= 0)
- result = XC_RESULT_I2C_WRITE_FAILURE;
+ if (watch_dog_timer <= 0)
+ result = -EREMOTEIO;
return result;
}
@@ -375,13 +370,13 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
len = i2c_sequence[index] * 256 + i2c_sequence[index+1];
if (len == 0x0000) {
/* RESET command */
- result = xc5000_TunerReset(fe);
+ result = xc5000_tuner_reset(fe);
index += 2;
- if (result != XC_RESULT_SUCCESS)
+ if (result != 0)
return result;
} else if (len & 0x8000) {
/* WAIT command */
- xc_wait(len & 0x7FFF);
+ msleep(len & 0x7FFF);
index += 2;
} else {
/* Send i2c data whilst ensuring individual transactions
@@ -404,7 +399,7 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
result = xc_send_i2c_data(priv, buf,
nbytes_to_send);
- if (result != XC_RESULT_SUCCESS)
+ if (result != 0)
return result;
pos += nbytes_to_send - 2;
@@ -412,7 +407,7 @@ static int xc_load_i2c_sequence(struct dvb_frontend *fe, const u8 *i2c_sequence)
index += len;
}
}
- return XC_RESULT_SUCCESS;
+ return 0;
}
static int xc_initialize(struct xc5000_priv *priv)
@@ -421,29 +416,29 @@ static int xc_initialize(struct xc5000_priv *priv)
return xc_write_reg(priv, XREG_INIT, 0);
}
-static int xc_SetTVStandard(struct xc5000_priv *priv,
- u16 VideoMode, u16 AudioMode, u8 RadioMode)
+static int xc_set_tv_standard(struct xc5000_priv *priv,
+ u16 video_mode, u16 audio_mode, u8 radio_mode)
{
int ret;
- dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, VideoMode, AudioMode);
- if (RadioMode) {
+ dprintk(1, "%s(0x%04x,0x%04x)\n", __func__, video_mode, audio_mode);
+ if (radio_mode) {
dprintk(1, "%s() Standard = %s\n",
__func__,
- XC5000_Standard[RadioMode].Name);
+ xc5000_standard[radio_mode].name);
} else {
dprintk(1, "%s() Standard = %s\n",
__func__,
- XC5000_Standard[priv->video_standard].Name);
+ xc5000_standard[priv->video_standard].name);
}
- ret = xc_write_reg(priv, XREG_VIDEO_MODE, VideoMode);
- if (ret == XC_RESULT_SUCCESS)
- ret = xc_write_reg(priv, XREG_AUDIO_MODE, AudioMode);
+ ret = xc_write_reg(priv, XREG_VIDEO_MODE, video_mode);
+ if (ret == 0)
+ ret = xc_write_reg(priv, XREG_AUDIO_MODE, audio_mode);
return ret;
}
-static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
+static int xc_set_signal_source(struct xc5000_priv *priv, u16 rf_mode)
{
dprintk(1, "%s(%d) Source = %s\n", __func__, rf_mode,
rf_mode == XC_RF_MODE_AIR ? "ANTENNA" : "CABLE");
@@ -459,7 +454,7 @@ static int xc_SetSignalSource(struct xc5000_priv *priv, u16 rf_mode)
static const struct dvb_tuner_ops xc5000_tuner_ops;
-static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
+static int xc_set_rf_frequency(struct xc5000_priv *priv, u32 freq_hz)
{
u16 freq_code;
@@ -467,7 +462,7 @@ static int xc_set_RF_frequency(struct xc5000_priv *priv, u32 freq_hz)
if ((freq_hz > xc5000_tuner_ops.info.frequency_max) ||
(freq_hz < xc5000_tuner_ops.info.frequency_min))
- return XC_RESULT_OUT_OF_RANGE;
+ return -EINVAL;
freq_code = (u16)(freq_hz / 15625);
@@ -488,7 +483,7 @@ static int xc_set_IF_frequency(struct xc5000_priv *priv, u32 freq_khz)
}
-static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
+static int xc_get_adc_envelope(struct xc5000_priv *priv, u16 *adc_envelope)
{
return xc5000_readreg(priv, XREG_ADC_ENV, adc_envelope);
}
@@ -496,14 +491,14 @@ static int xc_get_ADC_Envelope(struct xc5000_priv *priv, u16 *adc_envelope)
static int xc_get_frequency_error(struct xc5000_priv *priv, u32 *freq_error_hz)
{
int result;
- u16 regData;
+ u16 reg_data;
u32 tmp;
- result = xc5000_readreg(priv, XREG_FREQ_ERROR, &regData);
- if (result != XC_RESULT_SUCCESS)
+ result = xc5000_readreg(priv, XREG_FREQ_ERROR, &reg_data);
+ if (result != 0)
return result;
- tmp = (u32)regData;
+ tmp = (u32)reg_data;
(*freq_error_hz) = (tmp * 15625) / 1000;
return result;
}
@@ -521,7 +516,7 @@ static int xc_get_version(struct xc5000_priv *priv,
int result;
result = xc5000_readreg(priv, XREG_VERSION, &data);
- if (result != XC_RESULT_SUCCESS)
+ if (result != 0)
return result;
(*hw_majorversion) = (data >> 12) & 0x0F;
@@ -539,14 +534,14 @@ static int xc_get_buildversion(struct xc5000_priv *priv, u16 *buildrev)
static int xc_get_hsync_freq(struct xc5000_priv *priv, u32 *hsync_freq_hz)
{
- u16 regData;
+ u16 reg_data;
int result;
- result = xc5000_readreg(priv, XREG_HSYNC_FREQ, &regData);
- if (result != XC_RESULT_SUCCESS)
+ result = xc5000_readreg(priv, XREG_HSYNC_FREQ, &reg_data);
+ if (result != 0)
return result;
- (*hsync_freq_hz) = ((regData & 0x0fff) * 763)/100;
+ (*hsync_freq_hz) = ((reg_data & 0x0fff) * 763)/100;
return result;
}
@@ -570,19 +565,19 @@ static int xc_get_totalgain(struct xc5000_priv *priv, u16 *totalgain)
return xc5000_readreg(priv, XREG_TOTALGAIN, totalgain);
}
-static u16 WaitForLock(struct xc5000_priv *priv)
+static u16 wait_for_lock(struct xc5000_priv *priv)
{
- u16 lockState = 0;
- int watchDogCount = 40;
-
- while ((lockState == 0) && (watchDogCount > 0)) {
- xc_get_lock_status(priv, &lockState);
- if (lockState != 1) {
- xc_wait(5);
- watchDogCount--;
+ u16 lock_state = 0;
+ int watch_dog_count = 40;
+
+ while ((lock_state == 0) && (watch_dog_count > 0)) {
+ xc_get_lock_status(priv, &lock_state);
+ if (lock_state != 1) {
+ msleep(5);
+ watch_dog_count--;
}
}
- return lockState;
+ return lock_state;
}
#define XC_TUNE_ANALOG 0
@@ -593,11 +588,11 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode)
dprintk(1, "%s(%u)\n", __func__, freq_hz);
- if (xc_set_RF_frequency(priv, freq_hz) != XC_RESULT_SUCCESS)
+ if (xc_set_rf_frequency(priv, freq_hz) != 0)
return 0;
if (mode == XC_TUNE_ANALOG) {
- if (WaitForLock(priv) == 1)
+ if (wait_for_lock(priv) == 1)
found = 1;
}
@@ -607,7 +602,7 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode)
static int xc_set_xtal(struct dvb_frontend *fe)
{
struct xc5000_priv *priv = fe->tuner_priv;
- int ret = XC_RESULT_SUCCESS;
+ int ret = 0;
switch (priv->chip_id) {
default:
@@ -649,23 +644,22 @@ static int xc5000_fwupload(struct dvb_frontend *fe)
priv->i2c_props.adap->dev.parent);
if (ret) {
printk(KERN_ERR "xc5000: Upload failed. (file not found?)\n");
- ret = XC_RESULT_RESET_FAILURE;
goto out;
} else {
printk(KERN_DEBUG "xc5000: firmware read %Zu bytes.\n",
fw->size);
- ret = XC_RESULT_SUCCESS;
+ ret = 0;
}
if (fw->size != desired_fw->size) {
printk(KERN_ERR "xc5000: firmware incorrect size\n");
- ret = XC_RESULT_RESET_FAILURE;
+ ret = -EINVAL;
} else {
printk(KERN_INFO "xc5000: firmware uploading...\n");
ret = xc_load_i2c_sequence(fe, fw->data);
- if (XC_RESULT_SUCCESS == ret)
+ if (0 == ret)
ret = xc_set_xtal(fe);
- if (XC_RESULT_SUCCESS == ret)
+ if (0 == ret)
printk(KERN_INFO "xc5000: firmware upload complete...\n");
else
printk(KERN_ERR "xc5000: firmware upload failed...\n");
@@ -695,9 +689,9 @@ static void xc_debug_dump(struct xc5000_priv *priv)
* Frame Lines needs two frame times after initial lock
* before it is valid.
*/
- xc_wait(100);
+ msleep(100);
- xc_get_ADC_Envelope(priv, &adc_envelope);
+ xc_get_adc_envelope(priv, &adc_envelope);
dprintk(1, "*** ADC envelope (0-1023) = %d\n", adc_envelope);
xc_get_frequency_error(priv, &freq_error_hz);
@@ -744,7 +738,7 @@ static int xc5000_set_params(struct dvb_frontend *fe)
u32 freq = fe->dtv_property_cache.frequency;
u32 delsys = fe->dtv_property_cache.delivery_system;
- if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) {
+ if (xc_load_fw_and_init_tuner(fe, 0) != 0) {
dprintk(1, "Unable to load firmware and init tuner\n");
return -EINVAL;
}
@@ -820,24 +814,24 @@ static int xc5000_set_params(struct dvb_frontend *fe)
dprintk(1, "%s() frequency=%d (compensated to %d)\n",
__func__, freq, priv->freq_hz);
- ret = xc_SetSignalSource(priv, priv->rf_mode);
- if (ret != XC_RESULT_SUCCESS) {
+ ret = xc_set_signal_source(priv, priv->rf_mode);
+ if (ret != 0) {
printk(KERN_ERR
- "xc5000: xc_SetSignalSource(%d) failed\n",
+ "xc5000: xc_set_signal_source(%d) failed\n",
priv->rf_mode);
return -EREMOTEIO;
}
- ret = xc_SetTVStandard(priv,
- XC5000_Standard[priv->video_standard].VideoMode,
- XC5000_Standard[priv->video_standard].AudioMode, 0);
- if (ret != XC_RESULT_SUCCESS) {
- printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+ ret = xc_set_tv_standard(priv,
+ xc5000_standard[priv->video_standard].video_mode,
+ xc5000_standard[priv->video_standard].audio_mode, 0);
+ if (ret != 0) {
+ printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n");
return -EREMOTEIO;
}
ret = xc_set_IF_frequency(priv, priv->if_khz);
- if (ret != XC_RESULT_SUCCESS) {
+ if (ret != 0) {
printk(KERN_ERR "xc5000: xc_Set_IF_frequency(%d) failed\n",
priv->if_khz);
return -EIO;
@@ -862,15 +856,15 @@ static int xc5000_is_firmware_loaded(struct dvb_frontend *fe)
u16 id;
ret = xc5000_readreg(priv, XREG_PRODUCT_ID, &id);
- if (ret == XC_RESULT_SUCCESS) {
+ if (ret == 0) {
if (id == XC_PRODUCT_ID_FW_NOT_LOADED)
- ret = XC_RESULT_RESET_FAILURE;
+ ret = -ENOENT;
else
- ret = XC_RESULT_SUCCESS;
+ ret = 0;
}
dprintk(1, "%s() returns %s id = 0x%x\n", __func__,
- ret == XC_RESULT_SUCCESS ? "True" : "False", id);
+ ret == 0 ? "True" : "False", id);
return ret;
}
@@ -936,19 +930,19 @@ static int xc5000_set_tv_freq(struct dvb_frontend *fe,
}
tune_channel:
- ret = xc_SetSignalSource(priv, priv->rf_mode);
- if (ret != XC_RESULT_SUCCESS) {
+ ret = xc_set_signal_source(priv, priv->rf_mode);
+ if (ret != 0) {
printk(KERN_ERR
- "xc5000: xc_SetSignalSource(%d) failed\n",
+ "xc5000: xc_set_signal_source(%d) failed\n",
priv->rf_mode);
return -EREMOTEIO;
}
- ret = xc_SetTVStandard(priv,
- XC5000_Standard[priv->video_standard].VideoMode,
- XC5000_Standard[priv->video_standard].AudioMode, 0);
- if (ret != XC_RESULT_SUCCESS) {
- printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+ ret = xc_set_tv_standard(priv,
+ xc5000_standard[priv->video_standard].video_mode,
+ xc5000_standard[priv->video_standard].audio_mode, 0);
+ if (ret != 0) {
+ printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n");
return -EREMOTEIO;
}
@@ -966,7 +960,7 @@ tune_channel:
/* PLL is unlocked, force reload of the firmware */
dprintk(1, "xc5000: PLL not locked (0x%x). Reloading...\n",
pll_lock_status);
- if (xc_load_fw_and_init_tuner(fe, 1) != XC_RESULT_SUCCESS) {
+ if (xc_load_fw_and_init_tuner(fe, 1) != 0) {
printk(KERN_ERR "xc5000: Unable to reload fw\n");
return -EREMOTEIO;
}
@@ -993,11 +987,11 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe,
}
if (priv->radio_input == XC5000_RADIO_FM1)
- radio_input = FM_Radio_INPUT1;
+ radio_input = FM_RADIO_INPUT1;
else if (priv->radio_input == XC5000_RADIO_FM2)
- radio_input = FM_Radio_INPUT2;
+ radio_input = FM_RADIO_INPUT2;
else if (priv->radio_input == XC5000_RADIO_FM1_MONO)
- radio_input = FM_Radio_INPUT1_MONO;
+ radio_input = FM_RADIO_INPUT1_MONO;
else {
dprintk(1, "%s() unknown radio input %d\n", __func__,
priv->radio_input);
@@ -1008,18 +1002,18 @@ static int xc5000_set_radio_freq(struct dvb_frontend *fe,
priv->rf_mode = XC_RF_MODE_AIR;
- ret = xc_SetTVStandard(priv, XC5000_Standard[radio_input].VideoMode,
- XC5000_Standard[radio_input].AudioMode, radio_input);
+ ret = xc_set_tv_standard(priv, xc5000_standard[radio_input].video_mode,
+ xc5000_standard[radio_input].audio_mode, radio_input);
- if (ret != XC_RESULT_SUCCESS) {
- printk(KERN_ERR "xc5000: xc_SetTVStandard failed\n");
+ if (ret != 0) {
+ printk(KERN_ERR "xc5000: xc_set_tv_standard failed\n");
return -EREMOTEIO;
}
- ret = xc_SetSignalSource(priv, priv->rf_mode);
- if (ret != XC_RESULT_SUCCESS) {
+ ret = xc_set_signal_source(priv, priv->rf_mode);
+ if (ret != 0) {
printk(KERN_ERR
- "xc5000: xc_SetSignalSource(%d) failed\n",
+ "xc5000: xc_set_signal_source(%d) failed\n",
priv->rf_mode);
return -EREMOTEIO;
}
@@ -1044,7 +1038,7 @@ static int xc5000_set_analog_params(struct dvb_frontend *fe,
if (priv->i2c_props.adap == NULL)
return -EINVAL;
- if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) {
+ if (xc_load_fw_and_init_tuner(fe, 0) != 0) {
dprintk(1, "Unable to load firmware and init tuner\n");
return -EINVAL;
}
@@ -1105,23 +1099,25 @@ static int xc5000_get_status(struct dvb_frontend *fe, u32 *status)
static int xc_load_fw_and_init_tuner(struct dvb_frontend *fe, int force)
{
struct xc5000_priv *priv = fe->tuner_priv;
- int ret = XC_RESULT_SUCCESS;
+ int ret = 0;
u16 pll_lock_status;
u16 fw_ck;
- if (force || xc5000_is_firmware_loaded(fe) != XC_RESULT_SUCCESS) {
+ cancel_delayed_work(&priv->timer_sleep);
+
+ if (force || xc5000_is_firmware_loaded(fe) != 0) {
fw_retry:
ret = xc5000_fwupload(fe);
- if (ret != XC_RESULT_SUCCESS)
+ if (ret != 0)
return ret;
msleep(20);
if (priv->fw_checksum_supported) {
if (xc5000_readreg(priv, XREG_FW_CHECKSUM, &fw_ck)
- != XC_RESULT_SUCCESS) {
+ != 0) {
dprintk(1, "%s() FW checksum reading failed.\n",
__func__);
goto fw_retry;
@@ -1137,7 +1133,7 @@ fw_retry:
/* Start the tuner self-calibration process */
ret |= xc_initialize(priv);
- if (ret != XC_RESULT_SUCCESS)
+ if (ret != 0)
goto fw_retry;
/* Wait for calibration to complete.
@@ -1145,10 +1141,10 @@ fw_retry:
* I2C transactions until calibration is complete. This way we
* don't have to rely on clock stretching working.
*/
- xc_wait(100);
+ msleep(100);
if (priv->init_status_supported) {
- if (xc5000_readreg(priv, XREG_INIT_STATUS, &fw_ck) != XC_RESULT_SUCCESS) {
+ if (xc5000_readreg(priv, XREG_INIT_STATUS, &fw_ck) != 0) {
dprintk(1, "%s() FW failed reading init status.\n",
__func__);
goto fw_retry;
@@ -1177,27 +1173,39 @@ fw_retry:
return ret;
}
-static int xc5000_sleep(struct dvb_frontend *fe)
+static void xc5000_do_timer_sleep(struct work_struct *timer_sleep)
{
+ struct xc5000_priv *priv =container_of(timer_sleep, struct xc5000_priv,
+ timer_sleep.work);
+ struct dvb_frontend *fe = priv->fe;
int ret;
dprintk(1, "%s()\n", __func__);
- /* Avoid firmware reload on slow devices */
- if (no_poweroff)
- return 0;
-
/* According to Xceive technical support, the "powerdown" register
was removed in newer versions of the firmware. The "supported"
way to sleep the tuner is to pull the reset pin low for 10ms */
- ret = xc5000_TunerReset(fe);
- if (ret != XC_RESULT_SUCCESS) {
+ ret = xc5000_tuner_reset(fe);
+ if (ret != 0)
printk(KERN_ERR
"xc5000: %s() unable to shutdown tuner\n",
__func__);
- return -EREMOTEIO;
- } else
- return XC_RESULT_SUCCESS;
+}
+
+static int xc5000_sleep(struct dvb_frontend *fe)
+{
+ struct xc5000_priv *priv = fe->tuner_priv;
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* Avoid firmware reload on slow devices */
+ if (no_poweroff)
+ return 0;
+
+ schedule_delayed_work(&priv->timer_sleep,
+ msecs_to_jiffies(XC5000_SLEEP_TIME));
+
+ return 0;
}
static int xc5000_init(struct dvb_frontend *fe)
@@ -1205,7 +1213,7 @@ static int xc5000_init(struct dvb_frontend *fe)
struct xc5000_priv *priv = fe->tuner_priv;
dprintk(1, "%s()\n", __func__);
- if (xc_load_fw_and_init_tuner(fe, 0) != XC_RESULT_SUCCESS) {
+ if (xc_load_fw_and_init_tuner(fe, 0) != 0) {
printk(KERN_ERR "xc5000: Unable to initialise tuner\n");
return -EREMOTEIO;
}
@@ -1224,8 +1232,10 @@ static int xc5000_release(struct dvb_frontend *fe)
mutex_lock(&xc5000_list_mutex);
- if (priv)
+ if (priv) {
+ cancel_delayed_work(&priv->timer_sleep);
hybrid_tuner_release_state(priv);
+ }
mutex_unlock(&xc5000_list_mutex);
@@ -1297,6 +1307,8 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
/* new tuner instance */
priv->bandwidth = 6000000;
fe->tuner_priv = priv;
+ priv->fe = fe;
+ INIT_DELAYED_WORK(&priv->timer_sleep, xc5000_do_timer_sleep);
break;
default:
/* existing tuner instance */
@@ -1327,7 +1339,7 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
/* Check if firmware has been loaded. It is possible that another
instance of the driver has loaded the firmware.
*/
- if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != XC_RESULT_SUCCESS)
+ if (xc5000_readreg(priv, XREG_PRODUCT_ID, &id) != 0)
goto fail;
switch (id) {
diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c
index 4ae8b1074649..d8b5d9480279 100644
--- a/drivers/media/usb/au0828/au0828-dvb.c
+++ b/drivers/media/usb/au0828/au0828-dvb.c
@@ -114,16 +114,20 @@ static void urb_completion(struct urb *purb)
int ptype = usb_pipetype(purb->pipe);
unsigned char *ptr;
- dprintk(2, "%s()\n", __func__);
+ dprintk(2, "%s: %d\n", __func__, purb->actual_length);
- if (!dev)
+ if (!dev) {
+ dprintk(2, "%s: no dev!\n", __func__);
return;
+ }
- if (dev->urb_streaming == 0)
+ if (dev->urb_streaming == 0) {
+ dprintk(2, "%s: not streaming!\n", __func__);
return;
+ }
if (ptype != PIPE_BULK) {
- printk(KERN_ERR "%s() Unsupported URB type %d\n",
+ printk(KERN_ERR "%s: Unsupported URB type %d\n",
__func__, ptype);
return;
}
@@ -252,8 +256,6 @@ static void au0828_stop_transport(struct au0828_dev *dev, int full_stop)
au0828_write(dev, 0x60b, 0x00);
}
-
-
static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
@@ -296,6 +298,8 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
dprintk(1, "%s()\n", __func__);
if (dvb) {
+ cancel_work_sync(&dev->restart_streaming);
+
mutex_lock(&dvb->lock);
dvb->stop_count++;
dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__,
@@ -338,6 +342,41 @@ static void au0828_restart_dvb_streaming(struct work_struct *work)
mutex_unlock(&dvb->lock);
}
+static int au0828_set_frontend(struct dvb_frontend *fe)
+{
+ struct au0828_dev *dev = fe->dvb->priv;
+ struct au0828_dvb *dvb = &dev->dvb;
+ int ret, was_streaming;
+
+ mutex_lock(&dvb->lock);
+ was_streaming = dev->urb_streaming;
+ if (was_streaming) {
+ au0828_stop_transport(dev, 1);
+
+ /*
+ * We can't hold a mutex here, as the restart_streaming
+ * kthread may also hold it.
+ */
+ mutex_unlock(&dvb->lock);
+ cancel_work_sync(&dev->restart_streaming);
+ mutex_lock(&dvb->lock);
+
+ stop_urb_transfer(dev);
+ }
+ mutex_unlock(&dvb->lock);
+
+ ret = dvb->set_frontend(fe);
+
+ if (was_streaming) {
+ mutex_lock(&dvb->lock);
+ au0828_start_transport(dev);
+ start_urb_transfer(dev);
+ mutex_unlock(&dvb->lock);
+ }
+
+ return ret;
+}
+
static int dvb_register(struct au0828_dev *dev)
{
struct au0828_dvb *dvb = &dev->dvb;
@@ -382,6 +421,10 @@ static int dvb_register(struct au0828_dev *dev)
goto fail_frontend;
}
+ /* Hook dvb frontend */
+ dvb->set_frontend = dvb->frontend->ops.set_frontend;
+ dvb->frontend->ops.set_frontend = au0828_set_frontend;
+
/* register demux stuff */
dvb->demux.dmx.capabilities =
DMX_TS_FILTERING | DMX_SECTION_FILTERING |
@@ -471,6 +514,8 @@ void au0828_dvb_unregister(struct au0828_dev *dev)
if (dvb->frontend == NULL)
return;
+ cancel_work_sync(&dev->restart_streaming);
+
dvb_net_release(&dvb->net);
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index f6154546b5c0..9038194513c5 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -1109,7 +1109,7 @@ static void au0828_init_tuner(struct au0828_dev *dev)
/* If we've never sent the standard in tuner core, do so now.
We don't do this at device probe because we don't want to
incur the cost of a firmware load */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->std);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->std);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
i2c_gate_ctrl(dev, 0);
}
@@ -1368,7 +1368,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
have to make the au0828 bridge adjust the size of its capture
buffer, which is currently hardcoded at 720x480 */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, norm);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, norm);
i2c_gate_ctrl(dev, 0);
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h
index 5439772c1551..7112b9d956fa 100644
--- a/drivers/media/usb/au0828/au0828.h
+++ b/drivers/media/usb/au0828/au0828.h
@@ -104,6 +104,8 @@ struct au0828_dvb {
int feeding;
int start_count;
int stop_count;
+
+ int (*set_frontend)(struct dvb_frontend *fe);
};
enum au0828_stream_state {
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index 2f63029e7a36..30a0c69fb42f 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -1516,7 +1516,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
dev->ts1.height = 576;
cx2341x_handler_set_50hz(&dev->mpeg_ctrl_handler, true);
}
- call_all(dev, core, s_std, dev->norm);
+ call_all(dev, video, s_std, dev->norm);
/* do mode control overrides */
cx231xx_do_mode_ctrl_overrides(dev);
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index 990626101718..1f8751379e24 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -1009,7 +1009,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
dev->width = 720;
dev->height = (dev->norm & V4L2_STD_625_50) ? 576 : 480;
- call_all(dev, core, s_std, dev->norm);
+ call_all(dev, video, s_std, dev->norm);
/* We need to reset basic properties in the decoder related to
resolution (since a standard change effects things like the number
@@ -1108,7 +1108,7 @@ int cx231xx_s_input(struct file *file, void *priv, unsigned int i)
/* There's a tuner, so reset the standard and put it on the
last known frequency (since it was probably powered down
until now */
- call_all(dev, core, s_std, dev->norm);
+ call_all(dev, video, s_std, dev->norm);
}
return 0;
@@ -2099,7 +2099,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
/* Set the initial input */
video_mux(dev, dev->video_input);
- call_all(dev, core, s_std, dev->norm);
+ call_all(dev, video, s_std, dev->norm);
v4l2_ctrl_handler_init(&dev->ctrl_handler, 10);
v4l2_ctrl_handler_init(&dev->radio_ctrl_handler, 5);
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index dcbd392e6efc..a676e4452847 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -1537,6 +1537,12 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
&rtl2832u_props, "Crypto ReDi PC 50 A", NULL) },
{ DVB_USB_DEVICE(USB_VID_KYE, 0x707f,
&rtl2832u_props, "Genius TVGo DVB-T03", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd395,
+ &rtl2832u_props, "Peak DVB-T USB", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20_RTL2832U,
+ &rtl2832u_props, "Sveon STV20", NULL) },
+ { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV27,
+ &rtl2832u_props, "Sveon STV27", NULL) },
/* RTL2832P devices: */
{ DVB_USB_DEVICE(USB_VID_HANFTEK, 0x0131,
diff --git a/drivers/media/usb/dvb-usb/az6027.c b/drivers/media/usb/dvb-usb/az6027.c
index c11138ebf6fb..0df52ab32a7b 100644
--- a/drivers/media/usb/dvb-usb/az6027.c
+++ b/drivers/media/usb/dvb-usb/az6027.c
@@ -1088,6 +1088,7 @@ static struct usb_device_id az6027_usb_table[] = {
{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V1) },
{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) },
{ USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) },
+ { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT_V2) },
{ },
};
@@ -1136,7 +1137,7 @@ static struct dvb_usb_device_properties az6027_properties = {
.i2c_algo = &az6027_i2c_algo,
- .num_device_descs = 6,
+ .num_device_descs = 7,
.devices = {
{
.name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)",
@@ -1162,6 +1163,10 @@ static struct dvb_usb_device_properties az6027_properties = {
.name = "Elgato EyeTV Sat",
.cold_ids = { &az6027_usb_table[5], NULL },
.warm_ids = { NULL },
+ }, {
+ .name = "Elgato EyeTV Sat",
+ .cold_ids = { &az6027_usb_table[6], NULL },
+ .warm_ids = { NULL },
},
{ NULL },
}
diff --git a/drivers/media/usb/dvb-usb/dib0700.h b/drivers/media/usb/dvb-usb/dib0700.h
index 637b6123f391..927617d95616 100644
--- a/drivers/media/usb/dvb-usb/dib0700.h
+++ b/drivers/media/usb/dvb-usb/dib0700.h
@@ -59,7 +59,7 @@ extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8
extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen);
extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw);
-extern int dib0700_rc_setup(struct dvb_usb_device *d);
+extern int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf);
extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
extern struct i2c_algorithm dib0700_i2c_algo;
extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c
index bf2a908d74cf..c14285fa8271 100644
--- a/drivers/media/usb/dvb-usb/dib0700_core.c
+++ b/drivers/media/usb/dvb-usb/dib0700_core.c
@@ -754,17 +754,20 @@ resubmit:
usb_submit_urb(purb, GFP_ATOMIC);
}
-int dib0700_rc_setup(struct dvb_usb_device *d)
+int dib0700_rc_setup(struct dvb_usb_device *d, struct usb_interface *intf)
{
struct dib0700_state *st = d->priv;
struct urb *purb;
- int ret;
+ const struct usb_endpoint_descriptor *e;
+ int ret, rc_ep = 1;
+ unsigned int pipe = 0;
/* Poll-based. Don't initialize bulk mode */
- if (st->fw_version < 0x10200)
+ if (st->fw_version < 0x10200 || !intf)
return 0;
/* Starting in firmware 1.20, the RC info is provided on a bulk pipe */
+
purb = usb_alloc_urb(0, GFP_KERNEL);
if (purb == NULL) {
err("rc usb alloc urb failed");
@@ -779,9 +782,35 @@ int dib0700_rc_setup(struct dvb_usb_device *d)
}
purb->status = -EINPROGRESS;
- usb_fill_bulk_urb(purb, d->udev, usb_rcvbulkpipe(d->udev, 1),
- purb->transfer_buffer, RC_MSG_SIZE_V1_20,
- dib0700_rc_urb_completion, d);
+
+ /*
+ * Some devices like the Hauppauge NovaTD model 52009 use an interrupt
+ * endpoint, while others use a bulk one.
+ */
+ e = &intf->altsetting[0].endpoint[rc_ep].desc;
+ if (usb_endpoint_dir_in(e)) {
+ if (usb_endpoint_xfer_bulk(e)) {
+ pipe = usb_rcvbulkpipe(d->udev, rc_ep);
+ usb_fill_bulk_urb(purb, d->udev, pipe,
+ purb->transfer_buffer,
+ RC_MSG_SIZE_V1_20,
+ dib0700_rc_urb_completion, d);
+
+ } else if (usb_endpoint_xfer_int(e)) {
+ pipe = usb_rcvintpipe(d->udev, rc_ep);
+ usb_fill_int_urb(purb, d->udev, pipe,
+ purb->transfer_buffer,
+ RC_MSG_SIZE_V1_20,
+ dib0700_rc_urb_completion, d, 1);
+ }
+ }
+
+ if (!pipe) {
+ err("There's no endpoint for remote controller");
+ kfree(purb->transfer_buffer);
+ usb_free_urb(purb);
+ return 0;
+ }
ret = usb_submit_urb(purb, GFP_ATOMIC);
if (ret) {
@@ -820,7 +849,7 @@ static int dib0700_probe(struct usb_interface *intf,
else
dev->props.rc.core.bulk_mode = false;
- dib0700_rc_setup(dev);
+ dib0700_rc_setup(dev, intf);
return 0;
}
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index 829323e42ca0..10e0db8d1850 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -514,7 +514,7 @@ static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
/* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]); */
- dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */
+ dib0700_rc_setup(d, NULL); /* reset ir sensor data to prevent false events */
d->last_event = 0;
switch (d->props.rc.core.protocol) {
diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c
index 98d24aefb640..d947e0379008 100644
--- a/drivers/media/usb/dvb-usb/technisat-usb2.c
+++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
@@ -214,10 +214,10 @@ static void technisat_usb2_frontend_reset(struct usb_device *udev)
/* LED control */
enum technisat_usb2_led_state {
- LED_OFF,
- LED_BLINK,
- LED_ON,
- LED_UNDEFINED
+ TECH_LED_OFF,
+ TECH_LED_BLINK,
+ TECH_LED_ON,
+ TECH_LED_UNDEFINED
};
static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum technisat_usb2_led_state state)
@@ -229,14 +229,14 @@ static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum techni
0
};
- if (disable_led_control && state != LED_OFF)
+ if (disable_led_control && state != TECH_LED_OFF)
return 0;
switch (state) {
- case LED_ON:
+ case TECH_LED_ON:
led[1] = 0x82;
break;
- case LED_BLINK:
+ case TECH_LED_BLINK:
led[1] = 0x82;
if (red) {
led[2] = 0x02;
@@ -251,7 +251,7 @@ static int technisat_usb2_set_led(struct dvb_usb_device *d, int red, enum techni
break;
default:
- case LED_OFF:
+ case TECH_LED_OFF:
led[1] = 0x80;
break;
}
@@ -310,11 +310,11 @@ static void technisat_usb2_green_led_control(struct work_struct *work)
goto schedule;
if (ber > 1000)
- technisat_usb2_set_led(state->dev, 0, LED_BLINK);
+ technisat_usb2_set_led(state->dev, 0, TECH_LED_BLINK);
else
- technisat_usb2_set_led(state->dev, 0, LED_ON);
+ technisat_usb2_set_led(state->dev, 0, TECH_LED_ON);
} else
- technisat_usb2_set_led(state->dev, 0, LED_OFF);
+ technisat_usb2_set_led(state->dev, 0, TECH_LED_OFF);
}
schedule:
@@ -365,9 +365,9 @@ static int technisat_usb2_power_ctrl(struct dvb_usb_device *d, int level)
return 0;
/* green led is turned off in any case - will be turned on when tuning */
- technisat_usb2_set_led(d, 0, LED_OFF);
+ technisat_usb2_set_led(d, 0, TECH_LED_OFF);
/* red led is turned on all the time */
- technisat_usb2_set_led(d, 1, LED_ON);
+ technisat_usb2_set_led(d, 1, TECH_LED_ON);
return 0;
}
@@ -667,7 +667,7 @@ static int technisat_usb2_rc_query(struct dvb_usb_device *d)
return 0;
if (!disable_led_control)
- technisat_usb2_set_led(d, 1, LED_BLINK);
+ technisat_usb2_set_led(d, 1, TECH_LED_BLINK);
return 0;
}
diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig
index d23a912096f7..f5d7198753c7 100644
--- a/drivers/media/usb/em28xx/Kconfig
+++ b/drivers/media/usb/em28xx/Kconfig
@@ -57,6 +57,8 @@ config VIDEO_EM28XX_DVB
select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
select DVB_DRX39XYJ if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
---help---
This adds support for DVB cards based on the
Empiatech em28xx chips.
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 342490f44ed2..e881ef7b6445 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -92,7 +92,7 @@ static void em28xx_audio_isocirq(struct urb *urb)
if (dev->disconnected) {
dprintk("device disconnected while streaming. URB status=%d.\n", urb->status);
- atomic_set(&dev->stream_started, 0);
+ atomic_set(&dev->adev.stream_started, 0);
return;
}
@@ -109,7 +109,7 @@ static void em28xx_audio_isocirq(struct urb *urb)
break;
}
- if (atomic_read(&dev->stream_started) == 0)
+ if (atomic_read(&dev->adev.stream_started) == 0)
return;
if (dev->adev.capture_pcm_substream) {
@@ -185,7 +185,7 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
em28xx_errdev("submit of audio urb failed (error=%i)\n",
errCode);
em28xx_deinit_isoc_audio(dev);
- atomic_set(&dev->stream_started, 0);
+ atomic_set(&dev->adev.stream_started, 0);
return errCode;
}
@@ -332,9 +332,9 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
dev->mute = 1;
mutex_lock(&dev->lock);
dev->adev.users--;
- if (atomic_read(&dev->stream_started) > 0) {
- atomic_set(&dev->stream_started, 0);
- schedule_work(&dev->wq_trigger);
+ if (atomic_read(&dev->adev.stream_started) > 0) {
+ atomic_set(&dev->adev.stream_started, 0);
+ schedule_work(&dev->adev.wq_trigger);
}
em28xx_audio_analog_set(dev);
@@ -381,12 +381,13 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream)
{
struct em28xx *dev = snd_pcm_substream_chip(substream);
+ struct em28xx_audio *adev = &dev->adev;
dprintk("Stop capture, if needed\n");
- if (atomic_read(&dev->stream_started) > 0) {
- atomic_set(&dev->stream_started, 0);
- schedule_work(&dev->wq_trigger);
+ if (atomic_read(&adev->stream_started) > 0) {
+ atomic_set(&adev->stream_started, 0);
+ schedule_work(&adev->wq_trigger);
}
return 0;
@@ -407,9 +408,11 @@ static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
static void audio_trigger(struct work_struct *work)
{
- struct em28xx *dev = container_of(work, struct em28xx, wq_trigger);
+ struct em28xx_audio *adev =
+ container_of(work, struct em28xx_audio, wq_trigger);
+ struct em28xx *dev = container_of(adev, struct em28xx, adev);
- if (atomic_read(&dev->stream_started)) {
+ if (atomic_read(&adev->stream_started)) {
dprintk("starting capture");
em28xx_init_audio_isoc(dev);
} else {
@@ -431,17 +434,17 @@ static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
case SNDRV_PCM_TRIGGER_START:
- atomic_set(&dev->stream_started, 1);
+ atomic_set(&dev->adev.stream_started, 1);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
case SNDRV_PCM_TRIGGER_STOP:
- atomic_set(&dev->stream_started, 0);
+ atomic_set(&dev->adev.stream_started, 0);
break;
default:
retval = -EINVAL;
}
- schedule_work(&dev->wq_trigger);
+ schedule_work(&dev->adev.wq_trigger);
return retval;
}
@@ -928,7 +931,7 @@ static int em28xx_audio_init(struct em28xx *dev)
strcpy(card->shortname, "Em28xx Audio");
strcpy(card->longname, "Empia Em28xx Audio");
- INIT_WORK(&dev->wq_trigger, audio_trigger);
+ INIT_WORK(&adev->wq_trigger, audio_trigger);
if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
em28xx_cvol_new(card, dev, "Video", AC97_VIDEO);
@@ -983,7 +986,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
if (dev->adev.sndcard) {
snd_card_disconnect(dev->adev.sndcard);
- flush_work(&dev->wq_trigger);
+ flush_work(&dev->adev.wq_trigger);
em28xx_audio_free_urb(dev);
@@ -1005,7 +1008,7 @@ static int em28xx_audio_suspend(struct em28xx *dev)
em28xx_info("Suspending audio extension");
em28xx_deinit_isoc_audio(dev);
- atomic_set(&dev->stream_started, 0);
+ atomic_set(&dev->adev.stream_started, 0);
return 0;
}
@@ -1019,7 +1022,7 @@ static int em28xx_audio_resume(struct em28xx *dev)
em28xx_info("Resuming audio extension");
/* Nothing to do other than schedule_work() ?? */
- schedule_work(&dev->wq_trigger);
+ schedule_work(&dev->adev.wq_trigger);
return 0;
}
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index 505e0505be04..12d4c0326e31 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -330,13 +330,14 @@ int em28xx_init_camera(struct em28xx *dev)
char clk_name[V4L2_SUBDEV_NAME_SIZE];
struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus];
struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus];
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
int ret = 0;
v4l2_clk_name_i2c(clk_name, sizeof(clk_name),
i2c_adapter_id(adap), client->addr);
- dev->clk = v4l2_clk_register_fixed(clk_name, "mclk", -EINVAL);
- if (IS_ERR(dev->clk))
- return PTR_ERR(dev->clk);
+ v4l2->clk = v4l2_clk_register_fixed(clk_name, "mclk", -EINVAL);
+ if (IS_ERR(v4l2->clk))
+ return PTR_ERR(v4l2->clk);
switch (dev->em28xx_sensor) {
case EM28XX_MT9V011:
@@ -348,8 +349,8 @@ int em28xx_init_camera(struct em28xx *dev)
.platform_data = &pdata,
};
- dev->sensor_xres = 640;
- dev->sensor_yres = 480;
+ v4l2->sensor_xres = 640;
+ v4l2->sensor_yres = 480;
/*
* FIXME: mt9v011 uses I2S speed as xtal clk - at least with
@@ -362,41 +363,41 @@ int em28xx_init_camera(struct em28xx *dev)
*/
dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ;
em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
- dev->sensor_xtal = 4300000;
- pdata.xtal = dev->sensor_xtal;
+ v4l2->sensor_xtal = 4300000;
+ pdata.xtal = v4l2->sensor_xtal;
if (NULL ==
- v4l2_i2c_new_subdev_board(&dev->v4l2_dev, adap,
+ v4l2_i2c_new_subdev_board(&dev->v4l2->v4l2_dev, adap,
&mt9v011_info, NULL)) {
ret = -ENODEV;
break;
}
/* probably means GRGB 16 bit bayer */
- dev->vinmode = 0x0d;
- dev->vinctl = 0x00;
+ v4l2->vinmode = 0x0d;
+ v4l2->vinctl = 0x00;
break;
}
case EM28XX_MT9M001:
- dev->sensor_xres = 1280;
- dev->sensor_yres = 1024;
+ v4l2->sensor_xres = 1280;
+ v4l2->sensor_yres = 1024;
em28xx_initialize_mt9m001(dev);
/* probably means BGGR 16 bit bayer */
- dev->vinmode = 0x0c;
- dev->vinctl = 0x00;
+ v4l2->vinmode = 0x0c;
+ v4l2->vinctl = 0x00;
break;
case EM28XX_MT9M111:
- dev->sensor_xres = 640;
- dev->sensor_yres = 512;
+ v4l2->sensor_xres = 640;
+ v4l2->sensor_yres = 512;
dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ;
em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
em28xx_initialize_mt9m111(dev);
- dev->vinmode = 0x0a;
- dev->vinctl = 0x00;
+ v4l2->vinmode = 0x0a;
+ v4l2->vinctl = 0x00;
break;
case EM28XX_OV2640:
@@ -418,11 +419,11 @@ int em28xx_init_camera(struct em28xx *dev)
* - adjust bridge xclk
* - disable 16 bit (12 bit) output formats on high resolutions
*/
- dev->sensor_xres = 640;
- dev->sensor_yres = 480;
+ v4l2->sensor_xres = 640;
+ v4l2->sensor_yres = 480;
subdev =
- v4l2_i2c_new_subdev_board(&dev->v4l2_dev, adap,
+ v4l2_i2c_new_subdev_board(&dev->v4l2->v4l2_dev, adap,
&ov2640_info, NULL);
if (NULL == subdev) {
ret = -ENODEV;
@@ -437,8 +438,8 @@ int em28xx_init_camera(struct em28xx *dev)
/* NOTE: for UXGA=1600x1200 switch to 12MHz */
dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ;
em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk);
- dev->vinmode = 0x08;
- dev->vinctl = 0x00;
+ v4l2->vinmode = 0x08;
+ v4l2->vinctl = 0x00;
break;
}
@@ -448,8 +449,8 @@ int em28xx_init_camera(struct em28xx *dev)
}
if (ret < 0) {
- v4l2_clk_unregister_fixed(dev->clk);
- dev->clk = NULL;
+ v4l2_clk_unregister_fixed(v4l2->clk);
+ v4l2->clk = NULL;
}
return ret;
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 50aa5a5317f2..15ad47045553 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -467,6 +467,18 @@ static struct em28xx_reg_seq speedlink_vad_laplace_reg_seq[] = {
{ -1, -1, -1, -1},
};
+static struct em28xx_reg_seq pctv_292e[] = {
+ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0},
+ {0x0d, 0xff, 0xff, 950},
+ {EM2874_R80_GPIO_P0_CTRL, 0xbd, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfd, 0xff, 410},
+ {EM2874_R80_GPIO_P0_CTRL, 0x7d, 0xff, 300},
+ {EM2874_R80_GPIO_P0_CTRL, 0x7c, 0xff, 60},
+ {0x0d, 0x42, 0xff, 50},
+ {EM2874_R5F_TS_ENABLE, 0x85, 0xff, 0},
+ {-1, -1, -1, -1},
+};
+
/*
* Button definitions
*/
@@ -2220,6 +2232,17 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
.ir_codes = RC_MAP_PINNACLE_PCTV_HD,
},
+ /* 2013:025f PCTV tripleStick (292e).
+ * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2157 */
+ [EM28178_BOARD_PCTV_292E] = {
+ .name = "PCTV tripleStick (292e)",
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = pctv_292e,
+ .has_dvb = 1,
+ .ir_codes = RC_MAP_PINNACLE_PCTV_HD,
+ },
};
EXPORT_SYMBOL_GPL(em28xx_boards);
@@ -2397,6 +2420,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE },
{ USB_DEVICE(0x2013, 0x0258),
.driver_info = EM28178_BOARD_PCTV_461E },
+ { USB_DEVICE(0x2013, 0x025f),
+ .driver_info = EM28178_BOARD_PCTV_292E },
{ },
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -2682,8 +2707,6 @@ static void em28xx_card_setup(struct em28xx *dev)
if (dev->board.is_webcam) {
if (em28xx_detect_sensor(dev) < 0)
dev->board.is_webcam = 0;
- else
- dev->progressive = 1;
}
switch (dev->model) {
@@ -2718,11 +2741,6 @@ static void em28xx_card_setup(struct em28xx *dev)
dev->board.name, dev->model);
dev->tuner_type = em28xx_boards[dev->model].tuner_type;
- if (em28xx_boards[dev->model].tuner_addr)
- dev->tuner_addr = em28xx_boards[dev->model].tuner_addr;
-
- if (em28xx_boards[dev->model].tda9887_conf)
- dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
/* request some modules */
switch (dev->model) {
@@ -2991,8 +3009,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
const char *chip_name = default_chip_name;
dev->udev = udev;
- mutex_init(&dev->vb_queue_lock);
- mutex_init(&dev->vb_vbi_queue_lock);
mutex_init(&dev->ctrl_urb_lock);
spin_lock_init(&dev->slock);
@@ -3416,15 +3432,14 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* Select USB transfer types to use */
if (has_video) {
- if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk))
- dev->analog_xfer_bulk = 1;
- em28xx_info("analog set to %s mode.\n",
- dev->analog_xfer_bulk ? "bulk" : "isoc");
+ if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk))
+ dev->analog_xfer_bulk = 1;
+ em28xx_info("analog set to %s mode.\n",
+ dev->analog_xfer_bulk ? "bulk" : "isoc");
}
if (has_dvb) {
- if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk))
- dev->dvb_xfer_bulk = 1;
-
+ if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk))
+ dev->dvb_xfer_bulk = 1;
em28xx_info("dvb set to %s mode.\n",
dev->dvb_xfer_bulk ? "bulk" : "isoc");
}
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index f599b18ef7ca..a121ed9561fd 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -55,6 +55,8 @@
#include "mb86a20s.h"
#include "m88ds3103.h"
#include "m88ts2022.h"
+#include "si2168.h"
+#include "si2157.h"
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
MODULE_LICENSE("GPL");
@@ -93,6 +95,7 @@ struct em28xx_dvb {
struct semaphore pll_mutex;
bool dont_attach_fe1;
int lna_gpio;
+ struct i2c_client *i2c_client_demod;
struct i2c_client *i2c_client_tuner;
};
@@ -743,6 +746,21 @@ static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe)
#endif
}
+static int em28xx_pctv_292e_set_lna(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
+ struct em28xx *dev = i2c_bus->dev;
+ u8 lna;
+
+ if (c->lna == 1)
+ lna = 0x01;
+ else
+ lna = 0x00;
+
+ return em28xx_write_reg_bits(dev, EM2874_R80_GPIO_P0_CTRL, lna, 0x01);
+}
+
static int em28xx_mt352_terratec_xs_init(struct dvb_frontend *fe)
{
/* Values extracted from a USB trace of the Terratec Windows driver */
@@ -1496,6 +1514,63 @@ static int em28xx_dvb_init(struct em28xx *dev)
dvb->i2c_client_tuner = client;
}
break;
+ case EM28178_BOARD_PCTV_292E:
+ {
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
+ struct i2c_board_info info;
+ struct si2168_config si2168_config;
+ struct si2157_config si2157_config;
+
+ /* attach demod */
+ si2168_config.i2c_adapter = &adapter;
+ si2168_config.fe = &dvb->fe[0];
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ info.addr = 0x64;
+ info.platform_data = &si2168_config;
+ request_module(info.type);
+ client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ dvb->i2c_client_demod = client;
+
+ /* attach tuner */
+ si2157_config.fe = dvb->fe[0];
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &si2157_config;
+ request_module(info.type);
+ client = i2c_new_device(adapter, &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ module_put(dvb->i2c_client_demod->dev.driver->owner);
+ i2c_unregister_device(dvb->i2c_client_demod);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ module_put(dvb->i2c_client_demod->dev.driver->owner);
+ i2c_unregister_device(dvb->i2c_client_demod);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ dvb->i2c_client_tuner = client;
+ dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna;
+ }
+ break;
default:
em28xx_errdev("/2: The frontend of your DVB/ATSC card"
" isn't supported yet\n");
@@ -1582,6 +1657,13 @@ static int em28xx_dvb_fini(struct em28xx *dev)
i2c_unregister_device(client);
}
+ /* remove I2C demod */
+ client = dvb->i2c_client_demod;
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
em28xx_unregister_dvb(dvb);
kfree(dvb);
dev->dvb = NULL;
@@ -1647,6 +1729,13 @@ static int em28xx_dvb_resume(struct em28xx *dev)
i2c_unregister_device(client);
}
+ /* remove I2C demod */
+ client = dvb->i2c_client_demod;
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
em28xx_unregister_dvb(dvb);
kfree(dvb);
dev->dvb = NULL;
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index ba6433c3a643..b58d4ebf6419 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -939,7 +939,6 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus,
dev->i2c_bus[bus].algo_type = algo_type;
dev->i2c_bus[bus].dev = dev;
dev->i2c_adap[bus].algo_data = &dev->i2c_bus[bus];
- i2c_set_adapdata(&dev->i2c_adap[bus], &dev->v4l2_dev);
retval = i2c_add_adapter(&dev->i2c_adap[bus]);
if (retval < 0) {
diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h
index bce438691e0e..432862c20bbf 100644
--- a/drivers/media/usb/em28xx/em28xx-v4l.h
+++ b/drivers/media/usb/em28xx/em28xx-v4l.h
@@ -16,5 +16,5 @@
int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
-int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
+void em28xx_stop_vbi_streaming(struct vb2_queue *vq);
extern struct vb2_ops em28xx_vbi_qops;
diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
index db3d655600df..6d7f657f6f55 100644
--- a/drivers/media/usb/em28xx/em28xx-vbi.c
+++ b/drivers/media/usb/em28xx/em28xx-vbi.c
@@ -47,12 +47,13 @@ static int vbi_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
unsigned int sizes[], void *alloc_ctxs[])
{
struct em28xx *dev = vb2_get_drv_priv(vq);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
unsigned long size;
if (fmt)
size = fmt->fmt.pix.sizeimage;
else
- size = dev->vbi_width * dev->vbi_height * 2;
+ size = v4l2->vbi_width * v4l2->vbi_height * 2;
if (0 == *nbuffers)
*nbuffers = 32;
@@ -69,11 +70,12 @@ static int vbi_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
static int vbi_buffer_prepare(struct vb2_buffer *vb)
{
- struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
- struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+ struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+ struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
unsigned long size;
- size = dev->vbi_width * dev->vbi_height * 2;
+ size = v4l2->vbi_width * v4l2->vbi_height * 2;
if (vb2_plane_size(vb, 0) < size) {
printk(KERN_INFO "%s data will not fit into plane (%lu < %lu)\n",
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 0856e5d367b6..f6b49c98e2c9 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -141,6 +141,33 @@ static struct em28xx_fmt format[] = {
},
};
+/*FIXME: maxw should be dependent of alt mode */
+static inline unsigned int norm_maxw(struct em28xx *dev)
+{
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+
+ if (dev->board.is_webcam)
+ return v4l2->sensor_xres;
+
+ if (dev->board.max_range_640_480)
+ return 640;
+
+ return 720;
+}
+
+static inline unsigned int norm_maxh(struct em28xx *dev)
+{
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+
+ if (dev->board.is_webcam)
+ return v4l2->sensor_yres;
+
+ if (dev->board.max_range_640_480)
+ return 480;
+
+ return (v4l2->norm & V4L2_STD_625_50) ? 576 : 480;
+}
+
static int em28xx_vbi_supported(struct em28xx *dev)
{
/* Modprobe option to manually disable */
@@ -166,10 +193,11 @@ static int em28xx_vbi_supported(struct em28xx *dev)
*/
static void em28xx_wake_i2c(struct em28xx *dev)
{
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0);
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
+ struct v4l2_device *v4l2_dev = &dev->v4l2->v4l2_dev;
+ v4l2_device_call_all(v4l2_dev, 0, core, reset, 0);
+ v4l2_device_call_all(v4l2_dev, 0, video, s_routing,
INPUT(dev->ctl_input)->vmux, 0, 0);
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+ v4l2_device_call_all(v4l2_dev, 0, video, s_stream, 0);
}
static int em28xx_colorlevels_set_default(struct em28xx *dev)
@@ -194,8 +222,9 @@ static int em28xx_set_outfmt(struct em28xx *dev)
{
int ret;
u8 fmt, vinctrl;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
- fmt = dev->format->reg;
+ fmt = v4l2->format->reg;
if (!dev->is_em25xx)
fmt |= 0x20;
/*
@@ -211,20 +240,20 @@ static int em28xx_set_outfmt(struct em28xx *dev)
if (ret < 0)
return ret;
- ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
+ ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, v4l2->vinmode);
if (ret < 0)
return ret;
- vinctrl = dev->vinctl;
+ vinctrl = v4l2->vinctl;
if (em28xx_vbi_supported(dev) == 1) {
vinctrl |= EM28XX_VINCTRL_VBI_RAW;
em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
- em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
- em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
- if (dev->norm & V4L2_STD_525_60) {
+ em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, v4l2->vbi_width/4);
+ em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, v4l2->vbi_height);
+ if (v4l2->norm & V4L2_STD_525_60) {
/* NTSC */
em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
- } else if (dev->norm & V4L2_STD_625_50) {
+ } else if (v4l2->norm & V4L2_STD_625_50) {
/* PAL */
em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
}
@@ -274,7 +303,7 @@ static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
{
- u8 mode;
+ u8 mode = 0x00;
/* the em2800 scaler only supports scaling down to 50% */
if (dev->board.is_em2800) {
@@ -293,22 +322,22 @@ static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
to work correctly */
mode = (h || v) ? 0x30 : 0x00;
}
- return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
+ return em28xx_write_reg(dev, EM28XX_R26_COMPR, mode);
}
/* FIXME: this only function read values from dev */
static int em28xx_resolution_set(struct em28xx *dev)
{
- int width, height;
- width = norm_maxw(dev);
- height = norm_maxh(dev);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+ int width = norm_maxw(dev);
+ int height = norm_maxh(dev);
/* Properly setup VBI */
- dev->vbi_width = 720;
- if (dev->norm & V4L2_STD_525_60)
- dev->vbi_height = 12;
+ v4l2->vbi_width = 720;
+ if (v4l2->norm & V4L2_STD_525_60)
+ v4l2->vbi_height = 12;
else
- dev->vbi_height = 18;
+ v4l2->vbi_height = 18;
em28xx_set_outfmt(dev);
@@ -326,15 +355,16 @@ static int em28xx_resolution_set(struct em28xx *dev)
else
em28xx_capture_area_set(dev, 0, 0, width, height);
- return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
+ return em28xx_scaler_set(dev, v4l2->hscale, v4l2->vscale);
}
/* Set USB alternate setting for analog video */
static int em28xx_set_alternate(struct em28xx *dev)
{
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
int errCode;
int i;
- unsigned int min_pkt_size = dev->width * 2 + 4;
+ unsigned int min_pkt_size = v4l2->width * 2 + 4;
/* NOTE: for isoc transfers, only alt settings > 0 are allowed
bulk transfers seem to work only with alt=0 ! */
@@ -351,7 +381,7 @@ static int em28xx_set_alternate(struct em28xx *dev)
the frame size should be increased, otherwise, only
green screen will be received.
*/
- if (dev->width * 2 * dev->height > 720 * 240 * 2)
+ if (v4l2->width * 2 * v4l2->height > 720 * 240 * 2)
min_pkt_size *= 2;
for (i = 0; i < dev->num_alt; i++) {
@@ -404,7 +434,7 @@ static inline void finish_buffer(struct em28xx *dev,
{
em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field);
- buf->vb.v4l2_buf.sequence = dev->field_count++;
+ buf->vb.v4l2_buf.sequence = dev->v4l2->field_count++;
buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
@@ -419,9 +449,10 @@ static void em28xx_copy_video(struct em28xx *dev,
unsigned char *usb_buf,
unsigned long len)
{
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
void *fieldstart, *startwrite, *startread;
int linesdone, currlinedone, offset, lencopy, remain;
- int bytesperline = dev->width << 1;
+ int bytesperline = v4l2->width << 1;
if (buf->pos + len > buf->length)
len = buf->length - buf->pos;
@@ -429,7 +460,7 @@ static void em28xx_copy_video(struct em28xx *dev,
startread = usb_buf;
remain = len;
- if (dev->progressive || buf->top_field)
+ if (v4l2->progressive || buf->top_field)
fieldstart = buf->vb_buf;
else /* interlaced mode, even nr. of lines */
fieldstart = buf->vb_buf + bytesperline;
@@ -437,7 +468,7 @@ static void em28xx_copy_video(struct em28xx *dev,
linesdone = buf->pos / bytesperline;
currlinedone = buf->pos % bytesperline;
- if (dev->progressive)
+ if (v4l2->progressive)
offset = linesdone * bytesperline + currlinedone;
else
offset = linesdone * bytesperline * 2 + currlinedone;
@@ -461,7 +492,7 @@ static void em28xx_copy_video(struct em28xx *dev,
remain -= lencopy;
while (remain > 0) {
- if (dev->progressive)
+ if (v4l2->progressive)
startwrite += lencopy;
else
startwrite += lencopy + bytesperline;
@@ -507,7 +538,7 @@ static void em28xx_copy_vbi(struct em28xx *dev,
offset = buf->pos;
/* Make sure the bottom field populates the second half of the frame */
if (buf->top_field == 0)
- offset += dev->vbi_width * dev->vbi_height;
+ offset += dev->v4l2->vbi_width * dev->v4l2->vbi_height;
memcpy(buf->vb_buf + offset, usb_buf, len);
buf->pos += len;
@@ -583,13 +614,15 @@ finish_field_prepare_next(struct em28xx *dev,
struct em28xx_buffer *buf,
struct em28xx_dmaqueue *dma_q)
{
- if (dev->progressive || dev->top_field) { /* Brand new frame */
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+
+ if (v4l2->progressive || v4l2->top_field) { /* Brand new frame */
if (buf != NULL)
finish_buffer(dev, buf);
buf = get_next_buf(dev, dma_q);
}
if (buf != NULL) {
- buf->top_field = dev->top_field;
+ buf->top_field = v4l2->top_field;
buf->pos = 0;
}
@@ -603,6 +636,7 @@ static inline void process_frame_data_em28xx(struct em28xx *dev,
unsigned char *data_pkt,
unsigned int data_len)
{
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct em28xx_buffer *buf = dev->usb_ctl.vid_buf;
struct em28xx_buffer *vbi_buf = dev->usb_ctl.vbi_buf;
struct em28xx_dmaqueue *dma_q = &dev->vidq;
@@ -622,17 +656,17 @@ static inline void process_frame_data_em28xx(struct em28xx *dev,
data_len -= 4;
} else if (data_pkt[0] == 0x33 && data_pkt[1] == 0x95) {
/* Field start (VBI mode) */
- dev->capture_type = 0;
- dev->vbi_read = 0;
+ v4l2->capture_type = 0;
+ v4l2->vbi_read = 0;
em28xx_isocdbg("VBI START HEADER !!!\n");
- dev->top_field = !(data_pkt[2] & 1);
+ v4l2->top_field = !(data_pkt[2] & 1);
data_pkt += 4;
data_len -= 4;
} else if (data_pkt[0] == 0x22 && data_pkt[1] == 0x5a) {
/* Field start (VBI disabled) */
- dev->capture_type = 2;
+ v4l2->capture_type = 2;
em28xx_isocdbg("VIDEO START HEADER !!!\n");
- dev->top_field = !(data_pkt[2] & 1);
+ v4l2->top_field = !(data_pkt[2] & 1);
data_pkt += 4;
data_len -= 4;
}
@@ -640,37 +674,37 @@ static inline void process_frame_data_em28xx(struct em28xx *dev,
/* NOTE: With bulk transfers, intermediate data packets
* have no continuation header */
- if (dev->capture_type == 0) {
+ if (v4l2->capture_type == 0) {
vbi_buf = finish_field_prepare_next(dev, vbi_buf, vbi_dma_q);
dev->usb_ctl.vbi_buf = vbi_buf;
- dev->capture_type = 1;
+ v4l2->capture_type = 1;
}
- if (dev->capture_type == 1) {
- int vbi_size = dev->vbi_width * dev->vbi_height;
- int vbi_data_len = ((dev->vbi_read + data_len) > vbi_size) ?
- (vbi_size - dev->vbi_read) : data_len;
+ if (v4l2->capture_type == 1) {
+ int vbi_size = v4l2->vbi_width * v4l2->vbi_height;
+ int vbi_data_len = ((v4l2->vbi_read + data_len) > vbi_size) ?
+ (vbi_size - v4l2->vbi_read) : data_len;
/* Copy VBI data */
if (vbi_buf != NULL)
em28xx_copy_vbi(dev, vbi_buf, data_pkt, vbi_data_len);
- dev->vbi_read += vbi_data_len;
+ v4l2->vbi_read += vbi_data_len;
if (vbi_data_len < data_len) {
/* Continue with copying video data */
- dev->capture_type = 2;
+ v4l2->capture_type = 2;
data_pkt += vbi_data_len;
data_len -= vbi_data_len;
}
}
- if (dev->capture_type == 2) {
+ if (v4l2->capture_type == 2) {
buf = finish_field_prepare_next(dev, buf, dma_q);
dev->usb_ctl.vid_buf = buf;
- dev->capture_type = 3;
+ v4l2->capture_type = 3;
}
- if (dev->capture_type == 3 && buf != NULL && data_len > 0)
+ if (v4l2->capture_type == 3 && buf != NULL && data_len > 0)
em28xx_copy_video(dev, buf, data_pkt, data_len);
}
@@ -683,6 +717,7 @@ static inline void process_frame_data_em25xx(struct em28xx *dev,
{
struct em28xx_buffer *buf = dev->usb_ctl.vid_buf;
struct em28xx_dmaqueue *dmaq = &dev->vidq;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
bool frame_end = 0;
/* Check for header */
@@ -691,7 +726,7 @@ static inline void process_frame_data_em25xx(struct em28xx *dev,
if (data_len >= 2) { /* em25xx header is only 2 bytes long */
if ((data_pkt[0] == EM25XX_FRMDATAHDR_BYTE1) &&
((data_pkt[1] & ~EM25XX_FRMDATAHDR_BYTE2_MASK) == 0x00)) {
- dev->top_field = !(data_pkt[1] &
+ v4l2->top_field = !(data_pkt[1] &
EM25XX_FRMDATAHDR_BYTE2_FRAME_ID);
frame_end = data_pkt[1] &
EM25XX_FRMDATAHDR_BYTE2_FRAME_END;
@@ -841,12 +876,14 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
unsigned int sizes[], void *alloc_ctxs[])
{
struct em28xx *dev = vb2_get_drv_priv(vq);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
unsigned long size;
if (fmt)
size = fmt->fmt.pix.sizeimage;
else
- size = (dev->width * dev->height * dev->format->depth + 7) >> 3;
+ size =
+ (v4l2->width * v4l2->height * v4l2->format->depth + 7) >> 3;
if (size == 0)
return -EINVAL;
@@ -864,12 +901,13 @@ static int
buffer_prepare(struct vb2_buffer *vb)
{
struct em28xx *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
unsigned long size;
em28xx_videodbg("%s, field=%d\n", __func__, vb->v4l2_buf.field);
- size = (dev->width * dev->height * dev->format->depth + 7) >> 3;
+ size = (v4l2->width * v4l2->height * v4l2->format->depth + 7) >> 3;
if (vb2_plane_size(vb, 0) < size) {
em28xx_videodbg("%s data will not fit into plane (%lu < %lu)\n",
@@ -884,6 +922,7 @@ buffer_prepare(struct vb2_buffer *vb)
int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
{
struct em28xx *dev = vb2_get_drv_priv(vq);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct v4l2_frequency f;
int rc = 0;
@@ -895,7 +934,7 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
if (rc)
return rc;
- if (dev->streaming_users == 0) {
+ if (v4l2->streaming_users == 0) {
/* First active streaming user, so allocate all the URBs */
/* Allocate the USB bandwidth */
@@ -906,7 +945,7 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
*/
em28xx_wake_i2c(dev);
- dev->capture_type = -1;
+ v4l2->capture_type = -1;
rc = em28xx_init_usb_xfer(dev, EM28XX_ANALOG_MODE,
dev->analog_xfer_bulk,
EM28XX_NUM_BUFS,
@@ -924,22 +963,24 @@ int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
/* Ask tuner to go to analog or radio mode */
memset(&f, 0, sizeof(f));
- f.frequency = dev->ctl_freq;
+ f.frequency = v4l2->frequency;
if (vq->owner && vq->owner->vdev->vfl_type == VFL_TYPE_RADIO)
f.type = V4L2_TUNER_RADIO;
else
f.type = V4L2_TUNER_ANALOG_TV;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+ v4l2_device_call_all(&v4l2->v4l2_dev,
+ 0, tuner, s_frequency, &f);
}
- dev->streaming_users++;
+ v4l2->streaming_users++;
return rc;
}
-static int em28xx_stop_streaming(struct vb2_queue *vq)
+static void em28xx_stop_streaming(struct vb2_queue *vq)
{
struct em28xx *dev = vb2_get_drv_priv(vq);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct em28xx_dmaqueue *vidq = &dev->vidq;
unsigned long flags = 0;
@@ -947,7 +988,7 @@ static int em28xx_stop_streaming(struct vb2_queue *vq)
res_free(dev, vq->type);
- if (dev->streaming_users-- == 1) {
+ if (v4l2->streaming_users-- == 1) {
/* Last active user, so shutdown all the URBS */
em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
}
@@ -961,13 +1002,12 @@ static int em28xx_stop_streaming(struct vb2_queue *vq)
}
dev->usb_ctl.vid_buf = NULL;
spin_unlock_irqrestore(&dev->slock, flags);
-
- return 0;
}
-int em28xx_stop_vbi_streaming(struct vb2_queue *vq)
+void em28xx_stop_vbi_streaming(struct vb2_queue *vq)
{
struct em28xx *dev = vb2_get_drv_priv(vq);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct em28xx_dmaqueue *vbiq = &dev->vbiq;
unsigned long flags = 0;
@@ -975,7 +1015,7 @@ int em28xx_stop_vbi_streaming(struct vb2_queue *vq)
res_free(dev, vq->type);
- if (dev->streaming_users-- == 1) {
+ if (v4l2->streaming_users-- == 1) {
/* Last active user, so shutdown all the URBS */
em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
}
@@ -989,8 +1029,6 @@ int em28xx_stop_vbi_streaming(struct vb2_queue *vq)
}
dev->usb_ctl.vbi_buf = NULL;
spin_unlock_irqrestore(&dev->slock, flags);
-
- return 0;
}
static void
@@ -1024,9 +1062,10 @@ static int em28xx_vb2_setup(struct em28xx *dev)
{
int rc;
struct vb2_queue *q;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
/* Setup Videobuf2 for Video capture */
- q = &dev->vb_vidq;
+ q = &v4l2->vb_vidq;
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
@@ -1040,7 +1079,7 @@ static int em28xx_vb2_setup(struct em28xx *dev)
return rc;
/* Setup Videobuf2 for VBI capture */
- q = &dev->vb_vbiq;
+ q = &v4l2->vb_vbiq;
q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
@@ -1060,6 +1099,7 @@ static int em28xx_vb2_setup(struct em28xx *dev)
static void video_mux(struct em28xx *dev, int index)
{
+ struct v4l2_device *v4l2_dev = &dev->v4l2->v4l2_dev;
dev->ctl_input = index;
dev->ctl_ainput = INPUT(index)->amux;
dev->ctl_aoutput = INPUT(index)->aout;
@@ -1067,21 +1107,21 @@ static void video_mux(struct em28xx *dev, int index)
if (!dev->ctl_aoutput)
dev->ctl_aoutput = EM28XX_AOUT_MASTER;
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
+ v4l2_device_call_all(v4l2_dev, 0, video, s_routing,
INPUT(index)->vmux, 0, 0);
if (dev->board.has_msp34xx) {
if (dev->i2s_speed) {
- v4l2_device_call_all(&dev->v4l2_dev, 0, audio,
+ v4l2_device_call_all(v4l2_dev, 0, audio,
s_i2s_clock_freq, dev->i2s_speed);
}
/* Note: this is msp3400 specific */
- v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
+ v4l2_device_call_all(v4l2_dev, 0, audio, s_routing,
dev->ctl_ainput, MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0);
}
if (dev->board.adecoder != EM28XX_NOADECODER) {
- v4l2_device_call_all(&dev->v4l2_dev, 0, audio, s_routing,
+ v4l2_device_call_all(v4l2_dev, 0, audio, s_routing,
dev->ctl_ainput, dev->ctl_aoutput, 0);
}
@@ -1112,7 +1152,9 @@ static void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct em28xx *dev = container_of(ctrl->handler, struct em28xx, ctrl_handler);
+ struct em28xx_v4l2 *v4l2 =
+ container_of(ctrl->handler, struct em28xx_v4l2, ctrl_handler);
+ struct em28xx *dev = v4l2->dev;
int ret = -EINVAL;
switch (ctrl->id) {
@@ -1187,19 +1229,20 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
- f->fmt.pix.width = dev->width;
- f->fmt.pix.height = dev->height;
- f->fmt.pix.pixelformat = dev->format->fourcc;
- f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
- f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
+ f->fmt.pix.width = v4l2->width;
+ f->fmt.pix.height = v4l2->height;
+ f->fmt.pix.pixelformat = v4l2->format->fourcc;
+ f->fmt.pix.bytesperline = (v4l2->width * v4l2->format->depth + 7) >> 3;
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * v4l2->height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
- if (dev->progressive)
+ if (v4l2->progressive)
f->fmt.pix.field = V4L2_FIELD_NONE;
else
- f->fmt.pix.field = dev->interlaced ?
+ f->fmt.pix.field = v4l2->interlaced_fieldmode ?
V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
return 0;
}
@@ -1220,6 +1263,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
unsigned int width = f->fmt.pix.width;
unsigned int height = f->fmt.pix.height;
unsigned int maxw = norm_maxw(dev);
@@ -1261,10 +1305,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.bytesperline = (width * fmt->depth + 7) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- if (dev->progressive)
+ if (v4l2->progressive)
f->fmt.pix.field = V4L2_FIELD_NONE;
else
- f->fmt.pix.field = dev->interlaced ?
+ f->fmt.pix.field = v4l2->interlaced_fieldmode ?
V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
f->fmt.pix.priv = 0;
@@ -1275,17 +1319,19 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
unsigned width, unsigned height)
{
struct em28xx_fmt *fmt;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
fmt = format_by_fourcc(fourcc);
if (!fmt)
return -EINVAL;
- dev->format = fmt;
- dev->width = width;
- dev->height = height;
+ v4l2->format = fmt;
+ v4l2->width = width;
+ v4l2->height = height;
/* set new image size */
- size_to_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+ size_to_scale(dev, v4l2->width, v4l2->height,
+ &v4l2->hscale, &v4l2->vscale);
em28xx_resolution_set(dev);
@@ -1296,8 +1342,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct em28xx *dev = video_drvdata(file);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
- if (dev->streaming_users > 0)
+ if (v4l2->streaming_users > 0)
return -EBUSY;
vidioc_try_fmt_vid_cap(file, priv, f);
@@ -1311,7 +1358,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- *norm = dev->norm;
+ *norm = dev->v4l2->norm;
return 0;
}
@@ -1321,24 +1368,25 @@ static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *norm)
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, querystd, norm);
+ v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, video, querystd, norm);
return 0;
}
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
struct v4l2_format f;
- if (norm == dev->norm)
+ if (norm == v4l2->norm)
return 0;
- if (dev->streaming_users > 0)
+ if (v4l2->streaming_users > 0)
return -EBUSY;
- dev->norm = norm;
+ v4l2->norm = norm;
/* Adjusts width/height, if needed */
f.fmt.pix.width = 720;
@@ -1346,12 +1394,13 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
vidioc_try_fmt_vid_cap(file, priv, &f);
/* set new image size */
- dev->width = f.fmt.pix.width;
- dev->height = f.fmt.pix.height;
- size_to_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
+ v4l2->width = f.fmt.pix.width;
+ v4l2->height = f.fmt.pix.height;
+ size_to_scale(dev, v4l2->width, v4l2->height,
+ &v4l2->hscale, &v4l2->vscale);
em28xx_resolution_set(dev);
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_std, v4l2->norm);
return 0;
}
@@ -1359,16 +1408,17 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
static int vidioc_g_parm(struct file *file, void *priv,
struct v4l2_streamparm *p)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
int rc = 0;
p->parm.capture.readbuffers = EM28XX_MIN_BUF;
if (dev->board.is_webcam)
- rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0,
+ rc = v4l2_device_call_until_err(&v4l2->v4l2_dev, 0,
video, g_parm, p);
else
- v4l2_video_std_frame_period(dev->norm,
+ v4l2_video_std_frame_period(v4l2->norm,
&p->parm.capture.timeperframe);
return rc;
@@ -1381,7 +1431,8 @@ static int vidioc_s_parm(struct file *file, void *priv,
struct em28xx *dev = fh->dev;
p->parm.capture.readbuffers = EM28XX_MIN_BUF;
- return v4l2_device_call_until_err(&dev->v4l2_dev, 0, video, s_parm, p);
+ return v4l2_device_call_until_err(&dev->v4l2->v4l2_dev,
+ 0, video, s_parm, p);
}
static const char *iname[] = {
@@ -1418,7 +1469,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
(EM28XX_VMUX_CABLE == INPUT(n)->type))
i->type = V4L2_INPUT_TYPE_TUNER;
- i->std = dev->vdev->tvnorms;
+ i->std = dev->v4l2->vdev->tvnorms;
/* webcams do not have the STD API */
if (dev->board.is_webcam)
i->capabilities = 0;
@@ -1520,7 +1571,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
strcpy(t->name, "Tuner");
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+ v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, g_tuner, t);
return 0;
}
@@ -1533,7 +1584,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+ v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, s_tuner, t);
return 0;
}
@@ -1542,27 +1593,29 @@ static int vidioc_g_frequency(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
if (0 != f->tuner)
return -EINVAL;
- f->frequency = dev->ctl_freq;
+ f->frequency = v4l2->frequency;
return 0;
}
static int vidioc_s_frequency(struct file *file, void *priv,
const struct v4l2_frequency *f)
{
- struct v4l2_frequency new_freq = *f;
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct v4l2_frequency new_freq = *f;
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
if (0 != f->tuner)
return -EINVAL;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_frequency, &new_freq);
- dev->ctl_freq = new_freq.frequency;
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, s_frequency, f);
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, g_frequency, &new_freq);
+ v4l2->frequency = new_freq.frequency;
return 0;
}
@@ -1579,7 +1632,8 @@ static int vidioc_g_chip_info(struct file *file, void *priv,
if (chip->match.addr == 1)
strlcpy(chip->name, "ac97", sizeof(chip->name));
else
- strlcpy(chip->name, dev->v4l2_dev.name, sizeof(chip->name));
+ strlcpy(chip->name,
+ dev->v4l2->v4l2_dev.name, sizeof(chip->name));
return 0;
}
@@ -1660,9 +1714,10 @@ static int vidioc_s_register(struct file *file, void *priv,
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct video_device *vdev = video_devdata(file);
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct video_device *vdev = video_devdata(file);
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
strlcpy(cap->driver, "em28xx", sizeof(cap->driver));
strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card));
@@ -1684,9 +1739,9 @@ static int vidioc_querycap(struct file *file, void *priv,
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS |
V4L2_CAP_READWRITE | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
- if (dev->vbi_dev)
+ if (v4l2->vbi_dev)
cap->capabilities |= V4L2_CAP_VBI_CAPTURE;
- if (dev->radio_dev)
+ if (v4l2->radio_dev)
cap->capabilities |= V4L2_CAP_RADIO;
return 0;
}
@@ -1751,24 +1806,25 @@ static int vidioc_enum_framesizes(struct file *file, void *priv,
static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *format)
{
- struct em28xx_fh *fh = priv;
- struct em28xx *dev = fh->dev;
+ struct em28xx_fh *fh = priv;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
- format->fmt.vbi.samples_per_line = dev->vbi_width;
+ format->fmt.vbi.samples_per_line = v4l2->vbi_width;
format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
format->fmt.vbi.offset = 0;
format->fmt.vbi.flags = 0;
format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
- format->fmt.vbi.count[0] = dev->vbi_height;
- format->fmt.vbi.count[1] = dev->vbi_height;
+ format->fmt.vbi.count[0] = v4l2->vbi_height;
+ format->fmt.vbi.count[1] = v4l2->vbi_height;
memset(format->fmt.vbi.reserved, 0, sizeof(format->fmt.vbi.reserved));
/* Varies by video standard (NTSC, PAL, etc.) */
- if (dev->norm & V4L2_STD_525_60) {
+ if (v4l2->norm & V4L2_STD_525_60) {
/* NTSC */
format->fmt.vbi.start[0] = 10;
format->fmt.vbi.start[1] = 273;
- } else if (dev->norm & V4L2_STD_625_50) {
+ } else if (v4l2->norm & V4L2_STD_625_50) {
/* PAL */
format->fmt.vbi.start[0] = 6;
format->fmt.vbi.start[1] = 318;
@@ -1791,7 +1847,7 @@ static int radio_g_tuner(struct file *file, void *priv,
strcpy(t->name, "Radio");
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
+ v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, g_tuner, t);
return 0;
}
@@ -1804,12 +1860,27 @@ static int radio_s_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
+ v4l2_device_call_all(&dev->v4l2->v4l2_dev, 0, tuner, s_tuner, t);
return 0;
}
/*
+ * em28xx_free_v4l2() - Free struct em28xx_v4l2
+ *
+ * @ref: struct kref for struct em28xx_v4l2
+ *
+ * Called when all users of struct em28xx_v4l2 are gone
+ */
+static void em28xx_free_v4l2(struct kref *ref)
+{
+ struct em28xx_v4l2 *v4l2 = container_of(ref, struct em28xx_v4l2, ref);
+
+ v4l2->dev->v4l2 = NULL;
+ kfree(v4l2);
+}
+
+/*
* em28xx_v4l2_open()
* inits the device and starts isoc transfer
*/
@@ -1817,6 +1888,7 @@ static int em28xx_v4l2_open(struct file *filp)
{
struct video_device *vdev = video_devdata(filp);
struct em28xx *dev = video_drvdata(filp);
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
enum v4l2_buf_type fh_type = 0;
struct em28xx_fh *fh;
@@ -1835,7 +1907,7 @@ static int em28xx_v4l2_open(struct file *filp)
em28xx_videodbg("open dev=%s type=%s users=%d\n",
video_device_node_name(vdev), v4l2_type_names[fh_type],
- dev->users);
+ v4l2->users);
if (mutex_lock_interruptible(&dev->lock))
return -ERESTARTSYS;
@@ -1850,7 +1922,7 @@ static int em28xx_v4l2_open(struct file *filp)
fh->type = fh_type;
filp->private_data = fh;
- if (dev->users == 0) {
+ if (v4l2->users == 0) {
em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
if (vdev->vfl_type != VFL_TYPE_RADIO)
@@ -1865,11 +1937,12 @@ static int em28xx_v4l2_open(struct file *filp)
if (vdev->vfl_type == VFL_TYPE_RADIO) {
em28xx_videodbg("video_open: setting radio device\n");
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_radio);
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, tuner, s_radio);
}
kref_get(&dev->ref);
- dev->users++;
+ kref_get(&v4l2->ref);
+ v4l2->users++;
mutex_unlock(&dev->lock);
v4l2_fh_add(&fh->fh);
@@ -1884,6 +1957,8 @@ static int em28xx_v4l2_open(struct file *filp)
*/
static int em28xx_v4l2_fini(struct em28xx *dev)
{
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+
if (dev->is_audio_only) {
/* Shouldn't initialize IR for this interface */
return 0;
@@ -1894,39 +1969,45 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
return 0;
}
+ if (v4l2 == NULL)
+ return 0;
+
em28xx_info("Closing video extension");
mutex_lock(&dev->lock);
- v4l2_device_disconnect(&dev->v4l2_dev);
+ v4l2_device_disconnect(&v4l2->v4l2_dev);
em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
- if (dev->radio_dev) {
+ if (v4l2->radio_dev) {
em28xx_info("V4L2 device %s deregistered\n",
- video_device_node_name(dev->radio_dev));
- video_unregister_device(dev->radio_dev);
+ video_device_node_name(v4l2->radio_dev));
+ video_unregister_device(v4l2->radio_dev);
}
- if (dev->vbi_dev) {
+ if (v4l2->vbi_dev) {
em28xx_info("V4L2 device %s deregistered\n",
- video_device_node_name(dev->vbi_dev));
- video_unregister_device(dev->vbi_dev);
+ video_device_node_name(v4l2->vbi_dev));
+ video_unregister_device(v4l2->vbi_dev);
}
- if (dev->vdev) {
+ if (v4l2->vdev) {
em28xx_info("V4L2 device %s deregistered\n",
- video_device_node_name(dev->vdev));
- video_unregister_device(dev->vdev);
+ video_device_node_name(v4l2->vdev));
+ video_unregister_device(v4l2->vdev);
}
- v4l2_ctrl_handler_free(&dev->ctrl_handler);
- v4l2_device_unregister(&dev->v4l2_dev);
+ v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
+ v4l2_device_unregister(&v4l2->v4l2_dev);
- if (dev->clk) {
- v4l2_clk_unregister_fixed(dev->clk);
- dev->clk = NULL;
+ if (v4l2->clk) {
+ v4l2_clk_unregister_fixed(v4l2->clk);
+ v4l2->clk = NULL;
}
+ kref_put(&v4l2->ref, em28xx_free_v4l2);
+
mutex_unlock(&dev->lock);
+
kref_put(&dev->ref, em28xx_free_device);
return 0;
@@ -1965,22 +2046,23 @@ static int em28xx_v4l2_resume(struct em28xx *dev)
*/
static int em28xx_v4l2_close(struct file *filp)
{
- struct em28xx_fh *fh = filp->private_data;
- struct em28xx *dev = fh->dev;
+ struct em28xx_fh *fh = filp->private_data;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
int errCode;
- em28xx_videodbg("users=%d\n", dev->users);
+ em28xx_videodbg("users=%d\n", v4l2->users);
vb2_fop_release(filp);
mutex_lock(&dev->lock);
- if (dev->users == 1) {
+ if (v4l2->users == 1) {
/* No sense to try to write to the device */
if (dev->disconnected)
goto exit;
/* Save some power by putting tuner to sleep */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, core, s_power, 0);
/* do this before setting alternate! */
em28xx_set_mode(dev, EM28XX_SUSPEND);
@@ -1996,30 +2078,14 @@ static int em28xx_v4l2_close(struct file *filp)
}
exit:
- dev->users--;
+ v4l2->users--;
+ kref_put(&v4l2->ref, em28xx_free_v4l2);
mutex_unlock(&dev->lock);
kref_put(&dev->ref, em28xx_free_device);
return 0;
}
-/*
- * em28xx_videodevice_release()
- * called when the last user of the video device exits and frees the memeory
- */
-static void em28xx_videodevice_release(struct video_device *vdev)
-{
- struct em28xx *dev = video_get_drvdata(vdev);
-
- video_device_release(vdev);
- if (vdev == dev->vdev)
- dev->vdev = NULL;
- else if (vdev == dev->vbi_dev)
- dev->vbi_dev = NULL;
- else if (vdev == dev->radio_dev)
- dev->radio_dev = NULL;
-}
-
static const struct v4l2_file_operations em28xx_v4l_fops = {
.owner = THIS_MODULE,
.open = em28xx_v4l2_open,
@@ -2076,7 +2142,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
static const struct video_device em28xx_video_template = {
.fops = &em28xx_v4l_fops,
.ioctl_ops = &video_ioctl_ops,
- .release = em28xx_videodevice_release,
+ .release = video_device_release,
.tvnorms = V4L2_STD_ALL,
};
@@ -2105,7 +2171,7 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
static struct video_device em28xx_radio_template = {
.fops = &radio_fops,
.ioctl_ops = &radio_ioctl_ops,
- .release = em28xx_videodevice_release,
+ .release = video_device_release,
};
/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
@@ -2139,7 +2205,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
return NULL;
*vfd = *template;
- vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->v4l2_dev = &dev->v4l2->v4l2_dev;
vfd->debug = video_debug;
vfd->lock = &dev->lock;
set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
@@ -2153,13 +2219,12 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
return vfd;
}
-static void em28xx_tuner_setup(struct em28xx *dev)
+static void em28xx_tuner_setup(struct em28xx *dev, unsigned short tuner_addr)
{
- struct tuner_setup tun_setup;
- struct v4l2_frequency f;
-
- if (dev->tuner_type == TUNER_ABSENT)
- return;
+ struct em28xx_v4l2 *v4l2 = dev->v4l2;
+ struct v4l2_device *v4l2_dev = &v4l2->v4l2_dev;
+ struct tuner_setup tun_setup;
+ struct v4l2_frequency f;
memset(&tun_setup, 0, sizeof(tun_setup));
@@ -2170,23 +2235,26 @@ static void em28xx_tuner_setup(struct em28xx *dev)
tun_setup.type = dev->board.radio.type;
tun_setup.addr = dev->board.radio_addr;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
+ v4l2_device_call_all(v4l2_dev,
+ 0, tuner, s_type_addr, &tun_setup);
}
if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) {
tun_setup.type = dev->tuner_type;
- tun_setup.addr = dev->tuner_addr;
+ tun_setup.addr = tuner_addr;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
+ v4l2_device_call_all(v4l2_dev,
+ 0, tuner, s_type_addr, &tun_setup);
}
- if (dev->tda9887_conf) {
+ if (dev->board.tda9887_conf) {
struct v4l2_priv_tun_config tda9887_cfg;
tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &dev->tda9887_conf;
+ tda9887_cfg.priv = &dev->board.tda9887_conf;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg);
+ v4l2_device_call_all(v4l2_dev,
+ 0, tuner, s_config, &tda9887_cfg);
}
if (dev->tuner_type == TUNER_XC2028) {
@@ -2201,15 +2269,15 @@ static void em28xx_tuner_setup(struct em28xx *dev)
xc2028_cfg.tuner = TUNER_XC2028;
xc2028_cfg.priv = &ctl;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg);
+ v4l2_device_call_all(v4l2_dev, 0, tuner, s_config, &xc2028_cfg);
}
/* configure tuner */
f.tuner = 0;
f.type = V4L2_TUNER_ANALOG_TV;
f.frequency = 9076; /* just a magic number */
- dev->ctl_freq = f.frequency;
- v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+ v4l2->frequency = f.frequency;
+ v4l2_device_call_all(v4l2_dev, 0, tuner, s_frequency, &f);
}
static int em28xx_v4l2_init(struct em28xx *dev)
@@ -2217,7 +2285,8 @@ static int em28xx_v4l2_init(struct em28xx *dev)
u8 val;
int ret;
unsigned int maxw;
- struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
+ struct v4l2_ctrl_handler *hdl;
+ struct em28xx_v4l2 *v4l2;
if (dev->is_audio_only) {
/* Shouldn't initialize IR for this interface */
@@ -2233,71 +2302,93 @@ static int em28xx_v4l2_init(struct em28xx *dev)
mutex_lock(&dev->lock);
- ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
+ v4l2 = kzalloc(sizeof(struct em28xx_v4l2), GFP_KERNEL);
+ if (v4l2 == NULL) {
+ em28xx_info("em28xx_v4l: memory allocation failed\n");
+ mutex_unlock(&dev->lock);
+ return -ENOMEM;
+ }
+ kref_init(&v4l2->ref);
+ v4l2->dev = dev;
+ dev->v4l2 = v4l2;
+
+ ret = v4l2_device_register(&dev->udev->dev, &v4l2->v4l2_dev);
if (ret < 0) {
em28xx_errdev("Call to v4l2_device_register() failed!\n");
goto err;
}
+ hdl = &v4l2->ctrl_handler;
v4l2_ctrl_handler_init(hdl, 8);
- dev->v4l2_dev.ctrl_handler = hdl;
+ v4l2->v4l2_dev.ctrl_handler = hdl;
+
+ if (dev->board.is_webcam)
+ v4l2->progressive = 1;
/*
* Default format, used for tvp5150 or saa711x output formats
*/
- dev->vinmode = 0x10;
- dev->vinctl = EM28XX_VINCTRL_INTERLACED |
- EM28XX_VINCTRL_CCIR656_ENABLE;
+ v4l2->vinmode = 0x10;
+ v4l2->vinctl = EM28XX_VINCTRL_INTERLACED |
+ EM28XX_VINCTRL_CCIR656_ENABLE;
/* request some modules */
if (dev->board.has_msp34xx)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "msp3400", 0, msp3400_addrs);
+ v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ "msp3400", 0, msp3400_addrs);
if (dev->board.decoder == EM28XX_SAA711X)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "saa7115_auto", 0, saa711x_addrs);
+ v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ "saa7115_auto", 0, saa711x_addrs);
if (dev->board.decoder == EM28XX_TVP5150)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "tvp5150", 0, tvp5150_addrs);
+ v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ "tvp5150", 0, tvp5150_addrs);
if (dev->board.adecoder == EM28XX_TVAUDIO)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "tvaudio", dev->board.tvaudio_addr, NULL);
+ v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ "tvaudio", dev->board.tvaudio_addr, NULL);
/* Initialize tuner and camera */
if (dev->board.tuner_type != TUNER_ABSENT) {
- int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
+ unsigned short tuner_addr = dev->board.tuner_addr;
+ int has_demod = (dev->board.tda9887_conf & TDA9887_PRESENT);
if (dev->board.radio.type)
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "tuner", dev->board.radio_addr, NULL);
+ v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ "tuner", dev->board.radio_addr, NULL);
if (has_demod)
- v4l2_i2c_new_subdev(&dev->v4l2_dev,
+ v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
&dev->i2c_adap[dev->def_i2c_bus], "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
- if (dev->tuner_addr == 0) {
+ if (tuner_addr == 0) {
enum v4l2_i2c_tuner_type type =
has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
struct v4l2_subdev *sd;
- sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+ sd = v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
&dev->i2c_adap[dev->def_i2c_bus], "tuner",
0, v4l2_i2c_tuner_addrs(type));
if (sd)
- dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
+ tuner_addr = v4l2_i2c_subdev_addr(sd);
} else {
- v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
- "tuner", dev->tuner_addr, NULL);
+ v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
+ &dev->i2c_adap[dev->def_i2c_bus],
+ "tuner", tuner_addr, NULL);
}
+
+ em28xx_tuner_setup(dev, tuner_addr);
}
- em28xx_tuner_setup(dev);
if (dev->em28xx_sensor != EM28XX_NOSENSOR)
em28xx_init_camera(dev);
@@ -2348,12 +2439,12 @@ static int em28xx_v4l2_init(struct em28xx *dev)
}
/* set default norm */
- dev->norm = V4L2_STD_PAL;
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
- dev->interlaced = EM28XX_INTERLACED_DEFAULT;
+ v4l2->norm = V4L2_STD_PAL;
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_std, v4l2->norm);
+ v4l2->interlaced_fieldmode = EM28XX_INTERLACED_DEFAULT;
/* Analog specific initialization */
- dev->format = &format[0];
+ v4l2->format = &format[0];
maxw = norm_maxw(dev);
/* MaxPacketSize for em2800 is too small to capture at full resolution
@@ -2376,74 +2467,75 @@ static int em28xx_v4l2_init(struct em28xx *dev)
(EM28XX_XCLK_AUDIO_UNMUTE | val));
em28xx_set_outfmt(dev);
- em28xx_compression_disable(dev);
/* Add image controls */
/* NOTE: at this point, the subdevices are already registered, so bridge
* controls are only added/enabled when no subdevice provides them */
- if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_CONTRAST))
- v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_CONTRAST))
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_CONTRAST,
0, 0x1f, 1, CONTRAST_DEFAULT);
- if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_BRIGHTNESS))
- v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_BRIGHTNESS))
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_BRIGHTNESS,
-0x80, 0x7f, 1, BRIGHTNESS_DEFAULT);
- if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_SATURATION))
- v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_SATURATION))
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_SATURATION,
0, 0x1f, 1, SATURATION_DEFAULT);
- if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_BLUE_BALANCE))
- v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_BLUE_BALANCE))
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_BLUE_BALANCE,
-0x30, 0x30, 1, BLUE_BALANCE_DEFAULT);
- if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_RED_BALANCE))
- v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_RED_BALANCE))
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_RED_BALANCE,
-0x30, 0x30, 1, RED_BALANCE_DEFAULT);
- if (NULL == v4l2_ctrl_find(&dev->ctrl_handler, V4L2_CID_SHARPNESS))
- v4l2_ctrl_new_std(&dev->ctrl_handler, &em28xx_ctrl_ops,
+ if (NULL == v4l2_ctrl_find(hdl, V4L2_CID_SHARPNESS))
+ v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
V4L2_CID_SHARPNESS,
0, 0x0f, 1, SHARPNESS_DEFAULT);
/* Reset image controls */
em28xx_colorlevels_set_default(dev);
- v4l2_ctrl_handler_setup(&dev->ctrl_handler);
- ret = dev->ctrl_handler.error;
+ v4l2_ctrl_handler_setup(hdl);
+ ret = hdl->error;
if (ret)
goto unregister_dev;
/* allocate and fill video video_device struct */
- dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
- if (!dev->vdev) {
+ v4l2->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
+ if (!v4l2->vdev) {
em28xx_errdev("cannot allocate video_device.\n");
ret = -ENODEV;
goto unregister_dev;
}
- dev->vdev->queue = &dev->vb_vidq;
- dev->vdev->queue->lock = &dev->vb_queue_lock;
+ mutex_init(&v4l2->vb_queue_lock);
+ mutex_init(&v4l2->vb_vbi_queue_lock);
+ v4l2->vdev->queue = &v4l2->vb_vidq;
+ v4l2->vdev->queue->lock = &v4l2->vb_queue_lock;
/* disable inapplicable ioctls */
if (dev->board.is_webcam) {
- v4l2_disable_ioctl(dev->vdev, VIDIOC_QUERYSTD);
- v4l2_disable_ioctl(dev->vdev, VIDIOC_G_STD);
- v4l2_disable_ioctl(dev->vdev, VIDIOC_S_STD);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_QUERYSTD);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_STD);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_STD);
} else {
- v4l2_disable_ioctl(dev->vdev, VIDIOC_S_PARM);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_PARM);
}
if (dev->tuner_type == TUNER_ABSENT) {
- v4l2_disable_ioctl(dev->vdev, VIDIOC_G_TUNER);
- v4l2_disable_ioctl(dev->vdev, VIDIOC_S_TUNER);
- v4l2_disable_ioctl(dev->vdev, VIDIOC_G_FREQUENCY);
- v4l2_disable_ioctl(dev->vdev, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_TUNER);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_FREQUENCY);
}
if (!dev->audio_mode.has_audio) {
- v4l2_disable_ioctl(dev->vdev, VIDIOC_G_AUDIO);
- v4l2_disable_ioctl(dev->vdev, VIDIOC_S_AUDIO);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_AUDIO);
}
/* register v4l2 video video_device */
- ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
+ ret = video_register_device(v4l2->vdev, VFL_TYPE_GRABBER,
video_nr[dev->devno]);
if (ret) {
em28xx_errdev("unable to register video device (error=%i).\n",
@@ -2453,27 +2545,27 @@ static int em28xx_v4l2_init(struct em28xx *dev)
/* Allocate and fill vbi video_device struct */
if (em28xx_vbi_supported(dev) == 1) {
- dev->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
+ v4l2->vbi_dev = em28xx_vdev_init(dev, &em28xx_video_template,
"vbi");
- dev->vbi_dev->queue = &dev->vb_vbiq;
- dev->vbi_dev->queue->lock = &dev->vb_vbi_queue_lock;
+ v4l2->vbi_dev->queue = &v4l2->vb_vbiq;
+ v4l2->vbi_dev->queue->lock = &v4l2->vb_vbi_queue_lock;
/* disable inapplicable ioctls */
- v4l2_disable_ioctl(dev->vdev, VIDIOC_S_PARM);
+ v4l2_disable_ioctl(v4l2->vdev, VIDIOC_S_PARM);
if (dev->tuner_type == TUNER_ABSENT) {
- v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_TUNER);
- v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_TUNER);
- v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_FREQUENCY);
- v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_FREQUENCY);
+ v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_TUNER);
+ v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_TUNER);
+ v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_FREQUENCY);
+ v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_FREQUENCY);
}
if (!dev->audio_mode.has_audio) {
- v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_G_AUDIO);
- v4l2_disable_ioctl(dev->vbi_dev, VIDIOC_S_AUDIO);
+ v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_G_AUDIO);
+ v4l2_disable_ioctl(v4l2->vbi_dev, VIDIOC_S_AUDIO);
}
/* register v4l2 vbi video_device */
- ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
+ ret = video_register_device(v4l2->vbi_dev, VFL_TYPE_VBI,
vbi_nr[dev->devno]);
if (ret < 0) {
em28xx_errdev("unable to register vbi device\n");
@@ -2482,32 +2574,32 @@ static int em28xx_v4l2_init(struct em28xx *dev)
}
if (em28xx_boards[dev->model].radio.type == EM28XX_RADIO) {
- dev->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
- "radio");
- if (!dev->radio_dev) {
+ v4l2->radio_dev = em28xx_vdev_init(dev, &em28xx_radio_template,
+ "radio");
+ if (!v4l2->radio_dev) {
em28xx_errdev("cannot allocate video_device.\n");
ret = -ENODEV;
goto unregister_dev;
}
- ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
+ ret = video_register_device(v4l2->radio_dev, VFL_TYPE_RADIO,
radio_nr[dev->devno]);
if (ret < 0) {
em28xx_errdev("can't register radio device\n");
goto unregister_dev;
}
em28xx_info("Registered radio device as %s\n",
- video_device_node_name(dev->radio_dev));
+ video_device_node_name(v4l2->radio_dev));
}
em28xx_info("V4L2 video device registered as %s\n",
- video_device_node_name(dev->vdev));
+ video_device_node_name(v4l2->vdev));
- if (dev->vbi_dev)
+ if (v4l2->vbi_dev)
em28xx_info("V4L2 VBI device registered as %s\n",
- video_device_node_name(dev->vbi_dev));
+ video_device_node_name(v4l2->vbi_dev));
/* Save some power by putting tuner to sleep */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+ v4l2_device_call_all(&v4l2->v4l2_dev, 0, core, s_power, 0);
/* initialize videobuf2 stuff */
em28xx_vb2_setup(dev);
@@ -2520,9 +2612,11 @@ static int em28xx_v4l2_init(struct em28xx *dev)
return 0;
unregister_dev:
- v4l2_ctrl_handler_free(&dev->ctrl_handler);
- v4l2_device_unregister(&dev->v4l2_dev);
+ v4l2_ctrl_handler_free(&v4l2->ctrl_handler);
+ v4l2_device_unregister(&v4l2->v4l2_dev);
err:
+ dev->v4l2 = NULL;
+ kref_put(&v4l2->ref, em28xx_free_v4l2);
mutex_unlock(&dev->lock);
return ret;
}
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index 2051fc9fb932..b4c837d77e5d 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -140,6 +140,7 @@
#define EM2765_BOARD_SPEEDLINK_VAD_LAPLACE 91
#define EM28178_BOARD_PCTV_461E 92
#define EM2874_BOARD_KWORLD_UB435Q_V3 93
+#define EM28178_BOARD_PCTV_292E 94
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
@@ -497,6 +498,60 @@ struct em28xx_eeprom {
#define EM28XX_RESOURCE_VIDEO 0x01
#define EM28XX_RESOURCE_VBI 0x02
+struct em28xx_v4l2 {
+ struct kref ref;
+ struct em28xx *dev;
+
+ struct v4l2_device v4l2_dev;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_clk *clk;
+
+ struct video_device *vdev;
+ struct video_device *vbi_dev;
+ struct video_device *radio_dev;
+
+ /* Videobuf2 */
+ struct vb2_queue vb_vidq;
+ struct vb2_queue vb_vbiq;
+ struct mutex vb_queue_lock;
+ struct mutex vb_vbi_queue_lock;
+
+ u8 vinmode;
+ u8 vinctl;
+
+ /* Camera specific fields */
+ int sensor_xres;
+ int sensor_yres;
+ int sensor_xtal;
+
+ int users; /* user count for exclusive use */
+ int streaming_users; /* number of actively streaming users */
+
+ u32 frequency; /* selected tuner frequency */
+
+ struct em28xx_fmt *format;
+ v4l2_std_id norm; /* selected tv norm */
+
+ /* Progressive/interlaced mode */
+ bool progressive;
+ int interlaced_fieldmode; /* 1=interlaced fields, 0=just top fields */
+ /* FIXME: everything else than interlaced_fieldmode=1 doesn't work */
+
+ /* Frame properties */
+ int width; /* current frame width */
+ int height; /* current frame height */
+ unsigned hscale; /* horizontal scale factor (see datasheet) */
+ unsigned vscale; /* vertical scale factor (see datasheet) */
+ unsigned int vbi_width;
+ unsigned int vbi_height; /* lines per field */
+
+ /* Capture state tracking */
+ int capture_type;
+ bool top_field;
+ int vbi_read;
+ unsigned int field_count;
+};
+
struct em28xx_audio {
char name[50];
unsigned num_urb;
@@ -513,6 +568,10 @@ struct em28xx_audio {
int users;
spinlock_t slock;
+
+ /* Controls streaming */
+ struct work_struct wq_trigger; /* trigger to start/stop audio */
+ atomic_t stream_started; /* stream should be running if true */
};
struct em28xx;
@@ -541,6 +600,12 @@ struct em28xx_i2c_bus {
struct em28xx {
struct kref ref;
+ /* Sub-module data */
+ struct em28xx_v4l2 *v4l2;
+ struct em28xx_dvb *dvb;
+ struct em28xx_audio adev;
+ struct em28xx_IR *ir;
+
/* generic device properties */
char name[30]; /* name (including minor) of the device */
int model; /* index in the device_data struct */
@@ -554,29 +619,9 @@ struct em28xx {
unsigned int has_alsa_audio:1;
unsigned int is_audio_only:1;
- struct v4l2_device v4l2_dev;
- struct v4l2_ctrl_handler ctrl_handler;
- struct v4l2_clk *clk;
struct em28xx_board board;
- /* Webcam specific fields */
- enum em28xx_sensor em28xx_sensor;
- int sensor_xres, sensor_yres;
- int sensor_xtal;
-
- /* Progressive (non-interlaced) mode */
- int progressive;
-
- /* Vinmode/Vinctl used at the driver */
- int vinmode, vinctl;
-
- /* Controls audio streaming */
- struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
- atomic_t stream_started; /* stream should be running if true */
-
- struct em28xx_fmt *format;
-
- struct em28xx_IR *ir;
+ enum em28xx_sensor em28xx_sensor; /* camera specific */
/* Some older em28xx chips needs a waiting time after writing */
unsigned int wait_after_write;
@@ -588,8 +633,6 @@ struct em28xx {
struct em28xx_audio_mode audio_mode;
int tuner_type; /* type of the tuner */
- int tuner_addr; /* tuner address */
- int tda9887_conf;
/* i2c i/o */
struct i2c_adapter i2c_adap[NUM_I2C_BUSES];
@@ -602,52 +645,21 @@ struct em28xx {
struct rt_mutex i2c_bus_lock;
/* video for linux */
- int users; /* user count for exclusive use */
- int streaming_users; /* Number of actively streaming users */
- struct video_device *vdev; /* video for linux device struct */
- v4l2_std_id norm; /* selected tv norm */
- int ctl_freq; /* selected frequency */
unsigned int ctl_input; /* selected input */
unsigned int ctl_ainput;/* selected audio input */
unsigned int ctl_aoutput;/* selected audio output */
int mute;
int volume;
- /* frame properties */
- int width; /* current frame width */
- int height; /* current frame height */
- unsigned hscale; /* horizontal scale factor (see datasheet) */
- unsigned vscale; /* vertical scale factor (see datasheet) */
- int interlaced; /* 1=interlace fileds, 0=just top fileds */
- unsigned int video_bytesread; /* Number of bytes read */
unsigned long hash; /* eeprom hash - for boards with generic ID */
unsigned long i2c_hash; /* i2c devicelist hash -
for boards with generic ID */
- struct em28xx_audio adev;
-
- /* capture state tracking */
- int capture_type;
- unsigned char top_field:1;
- int vbi_read;
- unsigned int vbi_width;
- unsigned int vbi_height; /* lines per field */
-
struct work_struct request_module_wk;
/* locks */
struct mutex lock;
struct mutex ctrl_urb_lock; /* protects urb_buf */
- /* spinlock_t queue_lock; */
- struct list_head inqueue, outqueue;
- struct video_device *vbi_dev;
- struct video_device *radio_dev;
-
- /* Videobuf2 */
- struct vb2_queue vb_vidq;
- struct vb2_queue vb_vbiq;
- struct mutex vb_queue_lock;
- struct mutex vb_vbi_queue_lock;
/* resources in use */
unsigned int resources;
@@ -662,9 +674,6 @@ struct em28xx {
struct em28xx_usb_ctl usb_ctl;
spinlock_t slock;
- unsigned int field_count;
- unsigned int vbi_field_count;
-
/* usb transfer */
struct usb_device *udev; /* the usb device */
u8 ifnum; /* number of the assigned usb interface */
@@ -708,8 +717,6 @@ struct em28xx {
/* Snapshot button input device */
char snapshot_button_path[30]; /* path of the input dev */
struct input_dev *sbutton_input_dev;
-
- struct em28xx_dvb *dvb;
};
#define kref_to_dev(d) container_of(d, struct em28xx, ref)
@@ -797,32 +804,4 @@ int em28xx_init_camera(struct em28xx *dev);
printk(KERN_WARNING "%s: "fmt,\
dev->name , ##arg); } while (0)
-static inline int em28xx_compression_disable(struct em28xx *dev)
-{
- /* side effect of disabling scaler and mixer */
- return em28xx_write_reg(dev, EM28XX_R26_COMPR, 0x00);
-}
-
-/*FIXME: maxw should be dependent of alt mode */
-static inline unsigned int norm_maxw(struct em28xx *dev)
-{
- if (dev->board.is_webcam)
- return dev->sensor_xres;
-
- if (dev->board.max_range_640_480)
- return 640;
-
- return 720;
-}
-
-static inline unsigned int norm_maxh(struct em28xx *dev)
-{
- if (dev->board.is_webcam)
- return dev->sensor_yres;
-
- if (dev->board.max_range_640_480)
- return 480;
-
- return (dev->norm & V4L2_STD_625_50) ? 576 : 480;
-}
#endif
diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig
index 4f0c6d566c85..eed10d782535 100644
--- a/drivers/media/usb/gspca/Kconfig
+++ b/drivers/media/usb/gspca/Kconfig
@@ -50,6 +50,16 @@ config USB_GSPCA_CPIA1
To compile this driver as a module, choose M here: the
module will be called gspca_cpia1.
+config USB_GSPCA_DTCS033
+ tristate "DTCS033 (Scopium) USB Astro-Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for the Scopium camera
+ for planetary astrophotography.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_dtcs033.
+
config USB_GSPCA_ETOMS
tristate "Etoms USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/drivers/media/usb/gspca/Makefile b/drivers/media/usb/gspca/Makefile
index 5855131ab8b6..f46975e4c82d 100644
--- a/drivers/media/usb/gspca/Makefile
+++ b/drivers/media/usb/gspca/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_USB_GSPCA) += gspca_main.o
obj-$(CONFIG_USB_GSPCA_BENQ) += gspca_benq.o
obj-$(CONFIG_USB_GSPCA_CONEX) += gspca_conex.o
obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o
+obj-$(CONFIG_USB_GSPCA_DTCS033) += gspca_dtcs033.o
obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o
obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o
obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o
@@ -48,6 +49,7 @@ gspca_main-objs := gspca.o autogain_functions.o
gspca_benq-objs := benq.o
gspca_conex-objs := conex.o
gspca_cpia1-objs := cpia1.o
+gspca_dtcs033-objs := dtcs033.o
gspca_etoms-objs := etoms.o
gspca_finepix-objs := finepix.o
gspca_jeilinj-objs := jeilinj.o
diff --git a/drivers/media/usb/gspca/dtcs033.c b/drivers/media/usb/gspca/dtcs033.c
new file mode 100644
index 000000000000..96bfd4e0f0eb
--- /dev/null
+++ b/drivers/media/usb/gspca/dtcs033.c
@@ -0,0 +1,441 @@
+/*
+ * Subdriver for Scopium astro-camera (DTCS033, 0547:7303)
+ *
+ * Copyright (C) 2014 Robert Butora (robert.butora.fi@gmail.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
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#define MODULE_NAME "dtcs033"
+#include "gspca.h"
+
+MODULE_AUTHOR("Robert Butora <robert.butora.fi@gmail.com>");
+MODULE_DESCRIPTION("Scopium DTCS033 astro-cam USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+struct dtcs033_usb_requests {
+ u8 bRequestType;
+ u8 bRequest;
+ u16 wValue;
+ u16 wIndex;
+ u16 wLength;
+};
+
+/* send a usb request */
+static void reg_rw(struct gspca_dev *gspca_dev,
+ u8 bRequestType, u8 bRequest,
+ u16 wValue, u16 wIndex, u16 wLength)
+{
+ struct usb_device *udev = gspca_dev->dev;
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+
+ ret = usb_control_msg(udev,
+ usb_rcvctrlpipe(udev, 0),
+ bRequest,
+ bRequestType,
+ wValue, wIndex,
+ gspca_dev->usb_buf, wLength, 500);
+
+ if (ret < 0) {
+ gspca_dev->usb_err = ret;
+ pr_err("usb_control_msg error %d\n", ret);
+ }
+
+ return;
+}
+/* send several usb in/out requests */
+static int reg_reqs(struct gspca_dev *gspca_dev,
+ const struct dtcs033_usb_requests *preqs, int n_reqs)
+{
+ int i = 0;
+ const struct dtcs033_usb_requests *preq;
+
+ while ((i < n_reqs) && (gspca_dev->usb_err >= 0)) {
+
+ preq = &preqs[i];
+
+ reg_rw(gspca_dev, preq->bRequestType, preq->bRequest,
+ preq->wValue, preq->wIndex, preq->wLength);
+
+ if (gspca_dev->usb_err < 0) {
+
+ PERR("usb error request no: %d / %d\n",
+ i, n_reqs);
+ } else if (preq->bRequestType & USB_DIR_IN) {
+
+ PDEBUG(D_STREAM,
+ "USB IN (%d) returned[%d] %02X %02X %02X %s",
+ i,
+ preq->wLength,
+ gspca_dev->usb_buf[0],
+ gspca_dev->usb_buf[1],
+ gspca_dev->usb_buf[2],
+ preq->wLength > 3 ? "...\n" : "\n");
+ }
+
+ i++;
+ }
+ return gspca_dev->usb_err;
+}
+
+/* -- subdriver interface implementation -- */
+
+#define DT_COLS (640)
+static const struct v4l2_pix_format dtcs033_mode[] = {
+ /* raw Bayer patterned output */
+ {DT_COLS, 480, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
+ .bytesperline = DT_COLS,
+ .sizeimage = DT_COLS*480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ },
+ /* this mode will demosaic the Bayer pattern */
+ {DT_COLS, 480, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE,
+ .bytesperline = DT_COLS,
+ .sizeimage = DT_COLS*480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ }
+};
+
+/* config called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ gspca_dev->cam.cam_mode = dtcs033_mode;
+ gspca_dev->cam.nmodes = ARRAY_SIZE(dtcs033_mode);
+
+ gspca_dev->cam.bulk = 1;
+ gspca_dev->cam.bulk_nurbs = 1;
+ gspca_dev->cam.bulk_size = DT_COLS*512;
+
+ return 0;
+}
+
+/* init called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ return 0;
+}
+
+/* start stop the camera */
+static int dtcs033_start(struct gspca_dev *gspca_dev);
+static void dtcs033_stopN(struct gspca_dev *gspca_dev);
+
+/* intercept camera image data */
+static void dtcs033_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* packet data */
+ int len) /* packet data length */
+{
+ /* drop incomplete frames */
+ if (len != DT_COLS*512) {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ /* gspca.c: discard invalidates the whole frame. */
+ return;
+ }
+
+ /* forward complete frames */
+ gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
+ gspca_frame_add(gspca_dev, INTER_PACKET,
+ data + 16*DT_COLS,
+ len - 32*DT_COLS); /* skip first & last 16 lines */
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+
+ return;
+}
+
+/* -- controls: exposure and gain -- */
+
+static void dtcs033_setexposure(struct gspca_dev *gspca_dev,
+ s32 expo, s32 gain)
+{
+ /* gain [dB] encoding */
+ u16 sGain = (u16)gain;
+ u16 gainVal = 224+(sGain-14)*(768-224)/(33-14);
+ u16 wIndex = 0x0100|(0x00FF&gainVal);
+ u16 wValue = (0xFF00&gainVal)>>8;
+
+ /* exposure time [msec] encoding */
+ u16 sXTime = (u16)expo;
+ u16 xtimeVal = (524*(150-(sXTime-1)))/150;
+
+ const u8 bRequestType =
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
+ const u8 bRequest = 0x18;
+
+ reg_rw(gspca_dev,
+ bRequestType, bRequest, wValue, wIndex, 0);
+ if (gspca_dev->usb_err < 0)
+ PERR("usb error in setexposure(gain) sequence.\n");
+
+ reg_rw(gspca_dev,
+ bRequestType, bRequest, (xtimeVal<<4), 0x6300, 0);
+ if (gspca_dev->usb_err < 0)
+ PERR("usb error in setexposure(time) sequence.\n");
+}
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev;/* !! must be the first item */
+
+ /* exposure & gain controls */
+ struct {
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *gain;
+ };
+};
+
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler,
+ struct gspca_dev, ctrl_handler);
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->usb_err = 0;
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ dtcs033_setexposure(gspca_dev,
+ ctrl->val, sd->gain->val);
+ break;
+ case V4L2_CID_GAIN:
+ dtcs033_setexposure(gspca_dev,
+ sd->exposure->val, ctrl->val);
+ break;
+ }
+ return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+ .s_ctrl = sd_s_ctrl,
+};
+
+static int dtcs033_init_controls(struct gspca_dev *gspca_dev)
+{
+ struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 2);
+ /* min max step default */
+ sd->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ 1, 150, 1, 75);/* [msec] */
+ sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_GAIN,
+ 14, 33, 1, 24);/* [dB] */
+ if (hdl->error) {
+ PERR("Could not initialize controls: %d\n",
+ hdl->error);
+ return hdl->error;
+ }
+
+ v4l2_ctrl_cluster(2, &sd->exposure);
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .config = sd_config,
+ .init = sd_init,
+ .start = dtcs033_start,
+ .stopN = dtcs033_stopN,
+ .pkt_scan = dtcs033_pkt_scan,
+ .init_controls = dtcs033_init_controls,
+};
+
+/* -- module initialisation -- */
+
+static const struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x0547, 0x7303)},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* device connect */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id,
+ &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+ .reset_resume = gspca_resume,
+#endif
+};
+module_usb_driver(sd_driver);
+
+
+/* ---------------------------------------------------------
+ USB requests to start/stop the camera [USB 2.0 spec Ch.9].
+
+ bRequestType :
+ 0x40 = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0xC0 = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+*/
+static const struct dtcs033_usb_requests dtcs033_start_reqs[] = {
+/* -- bRequest,wValue,wIndex,wLength */
+{ 0x40, 0x01, 0x0001, 0x000F, 0x0000 },
+{ 0x40, 0x01, 0x0000, 0x000F, 0x0000 },
+{ 0x40, 0x01, 0x0001, 0x000F, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x7F00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1001, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0004, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x7F01, 0x0000 },
+{ 0x40, 0x18, 0x30E0, 0x0009, 0x0000 },
+{ 0x40, 0x18, 0x0500, 0x012C, 0x0000 },
+{ 0x40, 0x18, 0x0380, 0x0200, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x035C, 0x0000 },
+{ 0x40, 0x18, 0x05C0, 0x0438, 0x0000 },
+{ 0x40, 0x18, 0x0440, 0x0500, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0668, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0700, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0800, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0900, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0A00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0B00, 0x0000 },
+{ 0x40, 0x18, 0x30E0, 0x6009, 0x0000 },
+{ 0x40, 0x18, 0x0500, 0x612C, 0x0000 },
+{ 0x40, 0x18, 0x2090, 0x6274, 0x0000 },
+{ 0x40, 0x18, 0x05C0, 0x6338, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6400, 0x0000 },
+{ 0x40, 0x18, 0x05C0, 0x6538, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6600, 0x0000 },
+{ 0x40, 0x18, 0x0680, 0x6744, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6800, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6900, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6A00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6B00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6C00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6D00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6E00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x808C, 0x0000 },
+{ 0x40, 0x18, 0x0010, 0x8101, 0x0000 },
+{ 0x40, 0x18, 0x30E0, 0x8200, 0x0000 },
+{ 0x40, 0x18, 0x0810, 0x832C, 0x0000 },
+{ 0x40, 0x18, 0x0680, 0x842B, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x8500, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x8600, 0x0000 },
+{ 0x40, 0x18, 0x0280, 0x8715, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x880C, 0x0000 },
+{ 0x40, 0x18, 0x0010, 0x8901, 0x0000 },
+{ 0x40, 0x18, 0x30E0, 0x8A00, 0x0000 },
+{ 0x40, 0x18, 0x0810, 0x8B2C, 0x0000 },
+{ 0x40, 0x18, 0x0680, 0x8C2B, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x8D00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x8E00, 0x0000 },
+{ 0x40, 0x18, 0x0280, 0x8F15, 0x0000 },
+{ 0x40, 0x18, 0x0010, 0xD040, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0xD100, 0x0000 },
+{ 0x40, 0x18, 0x00B0, 0xD20A, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0xD300, 0x0000 },
+{ 0x40, 0x18, 0x30E2, 0xD40D, 0x0000 },
+{ 0x40, 0x18, 0x0001, 0xD5C0, 0x0000 },
+{ 0x40, 0x18, 0x00A0, 0xD60A, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0xD700, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x7F00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1501, 0x0000 },
+{ 0x40, 0x18, 0x0001, 0x01FF, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0200, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0304, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1101, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1201, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1300, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1400, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1601, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1800, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1900, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1A00, 0x0000 },
+{ 0x40, 0x18, 0x2000, 0x1B00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1C00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x2100, 0x0000 },
+{ 0x40, 0x18, 0x00C0, 0x228E, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x3001, 0x0000 },
+{ 0x40, 0x18, 0x0010, 0x3101, 0x0000 },
+{ 0x40, 0x18, 0x0008, 0x3301, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x3400, 0x0000 },
+{ 0x40, 0x18, 0x0012, 0x3549, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x3620, 0x0000 },
+{ 0x40, 0x18, 0x0001, 0x3700, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x4000, 0x0000 },
+{ 0x40, 0x18, 0xFFFF, 0x41FF, 0x0000 },
+{ 0x40, 0x18, 0xFFFF, 0x42FF, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x500F, 0x0000 },
+{ 0x40, 0x18, 0x2272, 0x5108, 0x0000 },
+{ 0x40, 0x18, 0x2272, 0x5208, 0x0000 },
+{ 0x40, 0x18, 0xFFFF, 0x53FF, 0x0000 },
+{ 0x40, 0x18, 0xFFFF, 0x54FF, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6000, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6102, 0x0000 },
+{ 0x40, 0x18, 0x0010, 0x6214, 0x0000 },
+{ 0x40, 0x18, 0x0C80, 0x6300, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6401, 0x0000 },
+{ 0x40, 0x18, 0x0680, 0x6551, 0x0000 },
+{ 0x40, 0x18, 0xFFFF, 0x66FF, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6702, 0x0000 },
+{ 0x40, 0x18, 0x0010, 0x6800, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6900, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6A00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6B00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6C00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6D01, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6E00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x6F00, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x7000, 0x0000 },
+{ 0x40, 0x18, 0x0001, 0x7118, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x2001, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1101, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1301, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1300, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1501, 0x0000 },
+{ 0xC0, 0x11, 0x0000, 0x24C0, 0x0003 },
+{ 0x40, 0x18, 0x0000, 0x3000, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x3620, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x1501, 0x0000 },
+{ 0x40, 0x18, 0x0010, 0x6300, 0x0000 },
+{ 0x40, 0x18, 0x0002, 0x01F0, 0x0000 },
+{ 0x40, 0x01, 0x0003, 0x000F, 0x0000 }
+};
+
+static const struct dtcs033_usb_requests dtcs033_stop_reqs[] = {
+/* -- bRequest,wValue,wIndex,wLength */
+{ 0x40, 0x01, 0x0001, 0x000F, 0x0000 },
+{ 0x40, 0x01, 0x0000, 0x000F, 0x0000 },
+{ 0x40, 0x18, 0x0000, 0x0003, 0x0000 }
+};
+static int dtcs033_start(struct gspca_dev *gspca_dev)
+{
+ return reg_reqs(gspca_dev, dtcs033_start_reqs,
+ ARRAY_SIZE(dtcs033_start_reqs));
+}
+
+static void dtcs033_stopN(struct gspca_dev *gspca_dev)
+{
+ reg_reqs(gspca_dev, dtcs033_stop_reqs,
+ ARRAY_SIZE(dtcs033_stop_reqs));
+ return;
+}
diff --git a/drivers/media/usb/gspca/gl860/gl860-mi2020.c b/drivers/media/usb/gspca/gl860/gl860-mi2020.c
index 2edda6b7d653..a785828d4b9d 100644
--- a/drivers/media/usb/gspca/gl860/gl860-mi2020.c
+++ b/drivers/media/usb/gspca/gl860/gl860-mi2020.c
@@ -35,32 +35,34 @@ static u8 dat_hvflip5[] = {0x8c, 0xa1, 0x03};
static u8 dat_hvflip6[] = {0x90, 0x00, 0x06};
static struct idxdata tbl_middle_hvflip_low[] = {
- {0x33, "\x90\x00\x06"},
- {6, "\xff\xff\xff"},
- {0x33, "\x90\x00\x06"},
- {6, "\xff\xff\xff"},
- {0x33, "\x90\x00\x06"},
- {6, "\xff\xff\xff"},
- {0x33, "\x90\x00\x06"},
- {6, "\xff\xff\xff"},
+ {0x33, {0x90, 0x00, 0x06}},
+ {6, {0xff, 0xff, 0xff}},
+ {0x33, {0x90, 0x00, 0x06}},
+ {6, {0xff, 0xff, 0xff}},
+ {0x33, {0x90, 0x00, 0x06}},
+ {6, {0xff, 0xff, 0xff}},
+ {0x33, {0x90, 0x00, 0x06}},
+ {6, {0xff, 0xff, 0xff}},
};
static struct idxdata tbl_middle_hvflip_big[] = {
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa1\x20"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
- {102, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x20"},
- {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x01}},
+ {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x00}},
+ {102, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x02}},
+ {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x72}},
+ {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x01}},
};
static struct idxdata tbl_end_hvflip[] = {
- {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
- {6, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
- {6, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
- {6, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+ {0x33, {0x8c, 0xa1, 0x02}}, {0x33, {0x90, 0x00, 0x1f}},
+ {6, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x02}}, {0x33, {0x90, 0x00, 0x1f}},
+ {6, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x02}}, {0x33, {0x90, 0x00, 0x1f}},
+ {6, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x02}}, {0x33, {0x90, 0x00, 0x1f}},
};
static u8 dat_freq1[] = { 0x8c, 0xa4, 0x04 };
@@ -82,197 +84,267 @@ static struct validx tbl_common_0B[] = {
};
static struct idxdata tbl_common_3B[] = {
- {0x33, "\x86\x25\x01"}, {0x33, "\x86\x25\x00"},
- {2, "\xff\xff\xff"},
- {0x30, "\x1a\x0a\xcc"}, {0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"},
- {6, "\xff\xff\xff"}, /* 12 */
- {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
- {2, "\xff\xff\xff"}, /* - */
- {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\x22\x23"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0f"}, {0x33, "\x90\x00\x0d"},
- {0x33, "\x8c\xa2\x10"}, {0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x11"},
- {0x33, "\x90\x00\x07"}, {0x33, "\xf4\x03\x1d"}, {0x35, "\xa2\x00\xe2"},
- {0x33, "\x8c\xab\x05"}, {0x33, "\x90\x00\x01"}, {0x32, "\x6e\x00\x86"},
- {0x32, "\x70\x0f\xaa"}, {0x32, "\x72\x0f\xe4"}, {0x33, "\x8c\xa3\x4a"},
- {0x33, "\x90\x00\x5a"}, {0x33, "\x8c\xa3\x4b"}, {0x33, "\x90\x00\xa6"},
- {0x33, "\x8c\xa3\x61"}, {0x33, "\x90\x00\xc8"}, {0x33, "\x8c\xa3\x62"},
- {0x33, "\x90\x00\xe1"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
- {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
- {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
- {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"},
- {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"},
- {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"},
- {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"},
- {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"},
- {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"},
- {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"},
- {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"},
- {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"},
- {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"},
- {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"},
- {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"},
- {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"},
- {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"},
- {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"},
- {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"},
- {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"},
- {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"},
- {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"},
- {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"},
- {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
- {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
- {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
- {0x33, "\x78\x00\x00"},
- {2, "\xff\xff\xff"},
- {0x35, "\xb8\x1f\x20"}, {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x10"},
- {0x33, "\x8c\xa2\x07"}, {0x33, "\x90\x00\x08"}, {0x33, "\x8c\xa2\x42"},
- {0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x4a"}, {0x33, "\x90\x00\x8c"},
- {0x35, "\xba\xfa\x08"}, {0x33, "\x8c\xa2\x02"}, {0x33, "\x90\x00\x22"},
- {0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"}, {0x33, "\x8c\xa4\x04"},
- {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"}, {0x33, "\x90\x00\x00"},
- {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0c"},
- {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"}, {0x33, "\x90\x00\x04"},
- {0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"}, {0x33, "\x8c\xa1\x03"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"},
- {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x25"},
- {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"},
- {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x47"},
- {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x02\x84"},
- {0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"}, {0x33, "\x8c\x27\x07"},
- {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"}, {0x33, "\x90\x04\xb0"},
- {0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x0f"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"}, {0x33, "\x90\x04\xbd"},
- {0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"}, {0x33, "\x8c\x27\x15"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"},
- {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"}, {0x33, "\x8c\x27\x1b"},
- {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"}, {0x33, "\x90\x01\x02"},
- {0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"}, {0x33, "\x8c\x27\x21"},
- {0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"}, {0x33, "\x90\x02\x85"},
- {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x27"},
- {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"}, {0x33, "\x90\x20\x20"},
- {0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"}, {0x33, "\x8c\x27\x2d"},
- {0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"}, {0x33, "\x90\x00\x04"},
- {0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x33"},
- {0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"}, {0x33, "\x90\x06\x4b"},
- {0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x39"},
- {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"},
- {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x41"},
- {0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"}, {0x33, "\x90\x04\xed"},
- {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x51"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"}, {0x33, "\x90\x03\x20"},
- {0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x57"},
- {0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"}, {0x33, "\x90\x00\x00"},
- {0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x63"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"}, {0x33, "\x90\x04\xb0"},
- {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"}, {0x33, "\x8c\xa4\x08"},
- {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x21"},
- {0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\xa4\x0b"},
- {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa1"},
- {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"}, {0x33, "\x8c\x24\x15"},
- {0x33, "\x90\x00\x6a"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\x80"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
- {3, "\xff\xff\xff"},
+ {0x33, {0x86, 0x25, 0x01}}, {0x33, {0x86, 0x25, 0x00}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x30, {0x1a, 0x0a, 0xcc}}, {0x32, {0x02, 0x00, 0x08}},
+ {0x33, {0xf4, 0x03, 0x1d}},
+ {6, {0xff, 0xff, 0xff}}, /* 12 */
+ {0x34, {0x1e, 0x8f, 0x09}}, {0x34, {0x1c, 0x01, 0x28}},
+ {0x34, {0x1e, 0x8f, 0x09}},
+ {2, {0xff, 0xff, 0xff}}, /* - */
+ {0x34, {0x1e, 0x8f, 0x09}}, {0x32, {0x14, 0x06, 0xe6}},
+ {0x33, {0x8c, 0x22, 0x23}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0xa2, 0x0f}}, {0x33, {0x90, 0x00, 0x0d}},
+ {0x33, {0x8c, 0xa2, 0x10}}, {0x33, {0x90, 0x00, 0x0b}},
+ {0x33, {0x8c, 0xa2, 0x11}}, {0x33, {0x90, 0x00, 0x07}},
+ {0x33, {0xf4, 0x03, 0x1d}}, {0x35, {0xa2, 0x00, 0xe2}},
+ {0x33, {0x8c, 0xab, 0x05}}, {0x33, {0x90, 0x00, 0x01}},
+ {0x32, {0x6e, 0x00, 0x86}}, {0x32, {0x70, 0x0f, 0xaa}},
+ {0x32, {0x72, 0x0f, 0xe4}}, {0x33, {0x8c, 0xa3, 0x4a}},
+ {0x33, {0x90, 0x00, 0x5a}}, {0x33, {0x8c, 0xa3, 0x4b}},
+ {0x33, {0x90, 0x00, 0xa6}}, {0x33, {0x8c, 0xa3, 0x61}},
+ {0x33, {0x90, 0x00, 0xc8}}, {0x33, {0x8c, 0xa3, 0x62}},
+ {0x33, {0x90, 0x00, 0xe1}}, {0x34, {0xce, 0x01, 0xa8}},
+ {0x34, {0xd0, 0x66, 0x33}}, {0x34, {0xd2, 0x31, 0x9a}},
+ {0x34, {0xd4, 0x94, 0x63}}, {0x34, {0xd6, 0x4b, 0x25}},
+ {0x34, {0xd8, 0x26, 0x70}}, {0x34, {0xda, 0x72, 0x4c}},
+ {0x34, {0xdc, 0xff, 0x04}}, {0x34, {0xde, 0x01, 0x5b}},
+ {0x34, {0xe6, 0x01, 0x13}}, {0x34, {0xee, 0x0b, 0xf0}},
+ {0x34, {0xf6, 0x0b, 0xa4}}, {0x35, {0x00, 0xf6, 0xe7}},
+ {0x35, {0x08, 0x0d, 0xfd}}, {0x35, {0x10, 0x25, 0x63}},
+ {0x35, {0x18, 0x35, 0x6c}}, {0x35, {0x20, 0x42, 0x7e}},
+ {0x35, {0x28, 0x19, 0x44}}, {0x35, {0x30, 0x39, 0xd4}},
+ {0x35, {0x38, 0xf5, 0xa8}}, {0x35, {0x4c, 0x07, 0x90}},
+ {0x35, {0x44, 0x07, 0xb8}}, {0x35, {0x5c, 0x06, 0x88}},
+ {0x35, {0x54, 0x07, 0xff}}, {0x34, {0xe0, 0x01, 0x52}},
+ {0x34, {0xe8, 0x00, 0xcc}}, {0x34, {0xf0, 0x0d, 0x83}},
+ {0x34, {0xf8, 0x0c, 0xb3}}, {0x35, {0x02, 0xfe, 0xba}},
+ {0x35, {0x0a, 0x04, 0xe0}}, {0x35, {0x12, 0x1c, 0x63}},
+ {0x35, {0x1a, 0x2b, 0x5a}}, {0x35, {0x22, 0x32, 0x5e}},
+ {0x35, {0x2a, 0x0d, 0x28}}, {0x35, {0x32, 0x2c, 0x02}},
+ {0x35, {0x3a, 0xf4, 0xfa}}, {0x35, {0x4e, 0x07, 0xef}},
+ {0x35, {0x46, 0x07, 0x88}}, {0x35, {0x5e, 0x07, 0xc1}},
+ {0x35, {0x56, 0x04, 0x64}}, {0x34, {0xe4, 0x01, 0x15}},
+ {0x34, {0xec, 0x00, 0x82}}, {0x34, {0xf4, 0x0c, 0xce}},
+ {0x34, {0xfc, 0x0c, 0xba}}, {0x35, {0x06, 0x1f, 0x02}},
+ {0x35, {0x0e, 0x02, 0xe3}}, {0x35, {0x16, 0x1a, 0x50}},
+ {0x35, {0x1e, 0x24, 0x39}}, {0x35, {0x26, 0x23, 0x4c}},
+ {0x35, {0x2e, 0xf9, 0x1b}}, {0x35, {0x36, 0x23, 0x19}},
+ {0x35, {0x3e, 0x12, 0x08}}, {0x35, {0x52, 0x07, 0x22}},
+ {0x35, {0x4a, 0x03, 0xd3}}, {0x35, {0x62, 0x06, 0x54}},
+ {0x35, {0x5a, 0x04, 0x5d}}, {0x34, {0xe2, 0x01, 0x04}},
+ {0x34, {0xea, 0x00, 0xa0}}, {0x34, {0xf2, 0x0c, 0xbc}},
+ {0x34, {0xfa, 0x0c, 0x5b}}, {0x35, {0x04, 0x17, 0xf2}},
+ {0x35, {0x0c, 0x02, 0x08}}, {0x35, {0x14, 0x28, 0x43}},
+ {0x35, {0x1c, 0x28, 0x62}}, {0x35, {0x24, 0x2b, 0x60}},
+ {0x35, {0x2c, 0x07, 0x33}}, {0x35, {0x34, 0x1f, 0xb0}},
+ {0x35, {0x3c, 0xed, 0xcd}}, {0x35, {0x50, 0x00, 0x06}},
+ {0x35, {0x48, 0x07, 0xff}}, {0x35, {0x60, 0x05, 0x89}},
+ {0x35, {0x58, 0x07, 0xff}}, {0x35, {0x40, 0x00, 0xa0}},
+ {0x35, {0x42, 0x00, 0x00}}, {0x32, {0x10, 0x01, 0xfc}},
+ {0x33, {0x8c, 0xa1, 0x18}}, {0x33, {0x90, 0x00, 0x3c}},
+ {0x33, {0x78, 0x00, 0x00}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x35, {0xb8, 0x1f, 0x20}}, {0x33, {0x8c, 0xa2, 0x06}},
+ {0x33, {0x90, 0x00, 0x10}}, {0x33, {0x8c, 0xa2, 0x07}},
+ {0x33, {0x90, 0x00, 0x08}}, {0x33, {0x8c, 0xa2, 0x42}},
+ {0x33, {0x90, 0x00, 0x0b}}, {0x33, {0x8c, 0xa2, 0x4a}},
+ {0x33, {0x90, 0x00, 0x8c}}, {0x35, {0xba, 0xfa, 0x08}},
+ {0x33, {0x8c, 0xa2, 0x02}}, {0x33, {0x90, 0x00, 0x22}},
+ {0x33, {0x8c, 0xa2, 0x03}}, {0x33, {0x90, 0x00, 0xbb}},
+ {0x33, {0x8c, 0xa4, 0x04}}, {0x33, {0x90, 0x00, 0x80}},
+ {0x33, {0x8c, 0xa7, 0x9d}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0xa7, 0x9e}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0xa2, 0x0c}}, {0x33, {0x90, 0x00, 0x17}},
+ {0x33, {0x8c, 0xa2, 0x15}}, {0x33, {0x90, 0x00, 0x04}},
+ {0x33, {0x8c, 0xa2, 0x14}}, {0x33, {0x90, 0x00, 0x20}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x17}}, {0x33, {0x90, 0x21, 0x11}},
+ {0x33, {0x8c, 0x27, 0x1b}}, {0x33, {0x90, 0x02, 0x4f}},
+ {0x33, {0x8c, 0x27, 0x25}}, {0x33, {0x90, 0x06, 0x0f}},
+ {0x33, {0x8c, 0x27, 0x39}}, {0x33, {0x90, 0x21, 0x11}},
+ {0x33, {0x8c, 0x27, 0x3d}}, {0x33, {0x90, 0x01, 0x20}},
+ {0x33, {0x8c, 0x27, 0x47}}, {0x33, {0x90, 0x09, 0x4c}},
+ {0x33, {0x8c, 0x27, 0x03}}, {0x33, {0x90, 0x02, 0x84}},
+ {0x33, {0x8c, 0x27, 0x05}}, {0x33, {0x90, 0x01, 0xe2}},
+ {0x33, {0x8c, 0x27, 0x07}}, {0x33, {0x90, 0x06, 0x40}},
+ {0x33, {0x8c, 0x27, 0x09}}, {0x33, {0x90, 0x04, 0xb0}},
+ {0x33, {0x8c, 0x27, 0x0d}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x0f}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x11}}, {0x33, {0x90, 0x04, 0xbd}},
+ {0x33, {0x8c, 0x27, 0x13}}, {0x33, {0x90, 0x06, 0x4d}},
+ {0x33, {0x8c, 0x27, 0x15}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x17}}, {0x33, {0x90, 0x21, 0x11}},
+ {0x33, {0x8c, 0x27, 0x19}}, {0x33, {0x90, 0x04, 0x6c}},
+ {0x33, {0x8c, 0x27, 0x1b}}, {0x33, {0x90, 0x02, 0x4f}},
+ {0x33, {0x8c, 0x27, 0x1d}}, {0x33, {0x90, 0x01, 0x02}},
+ {0x33, {0x8c, 0x27, 0x1f}}, {0x33, {0x90, 0x02, 0x79}},
+ {0x33, {0x8c, 0x27, 0x21}}, {0x33, {0x90, 0x01, 0x55}},
+ {0x33, {0x8c, 0x27, 0x23}}, {0x33, {0x90, 0x02, 0x85}},
+ {0x33, {0x8c, 0x27, 0x25}}, {0x33, {0x90, 0x06, 0x0f}},
+ {0x33, {0x8c, 0x27, 0x27}}, {0x33, {0x90, 0x20, 0x20}},
+ {0x33, {0x8c, 0x27, 0x29}}, {0x33, {0x90, 0x20, 0x20}},
+ {0x33, {0x8c, 0x27, 0x2b}}, {0x33, {0x90, 0x10, 0x20}},
+ {0x33, {0x8c, 0x27, 0x2d}}, {0x33, {0x90, 0x20, 0x07}},
+ {0x33, {0x8c, 0x27, 0x2f}}, {0x33, {0x90, 0x00, 0x04}},
+ {0x33, {0x8c, 0x27, 0x31}}, {0x33, {0x90, 0x00, 0x04}},
+ {0x33, {0x8c, 0x27, 0x33}}, {0x33, {0x90, 0x04, 0xbb}},
+ {0x33, {0x8c, 0x27, 0x35}}, {0x33, {0x90, 0x06, 0x4b}},
+ {0x33, {0x8c, 0x27, 0x37}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x39}}, {0x33, {0x90, 0x21, 0x11}},
+ {0x33, {0x8c, 0x27, 0x3b}}, {0x33, {0x90, 0x00, 0x24}},
+ {0x33, {0x8c, 0x27, 0x3d}}, {0x33, {0x90, 0x01, 0x20}},
+ {0x33, {0x8c, 0x27, 0x41}}, {0x33, {0x90, 0x01, 0x69}},
+ {0x33, {0x8c, 0x27, 0x45}}, {0x33, {0x90, 0x04, 0xed}},
+ {0x33, {0x8c, 0x27, 0x47}}, {0x33, {0x90, 0x09, 0x4c}},
+ {0x33, {0x8c, 0x27, 0x51}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x53}}, {0x33, {0x90, 0x03, 0x20}},
+ {0x33, {0x8c, 0x27, 0x55}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x57}}, {0x33, {0x90, 0x02, 0x58}},
+ {0x33, {0x8c, 0x27, 0x5f}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x61}}, {0x33, {0x90, 0x06, 0x40}},
+ {0x33, {0x8c, 0x27, 0x63}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x65}}, {0x33, {0x90, 0x04, 0xb0}},
+ {0x33, {0x8c, 0x22, 0x2e}}, {0x33, {0x90, 0x00, 0xa1}},
+ {0x33, {0x8c, 0xa4, 0x08}}, {0x33, {0x90, 0x00, 0x1f}},
+ {0x33, {0x8c, 0xa4, 0x09}}, {0x33, {0x90, 0x00, 0x21}},
+ {0x33, {0x8c, 0xa4, 0x0a}}, {0x33, {0x90, 0x00, 0x25}},
+ {0x33, {0x8c, 0xa4, 0x0b}}, {0x33, {0x90, 0x00, 0x27}},
+ {0x33, {0x8c, 0x24, 0x11}}, {0x33, {0x90, 0x00, 0xa1}},
+ {0x33, {0x8c, 0x24, 0x13}}, {0x33, {0x90, 0x00, 0xc1}},
+ {0x33, {0x8c, 0x24, 0x15}}, {0x33, {0x90, 0x00, 0x6a}},
+ {0x33, {0x8c, 0x24, 0x17}}, {0x33, {0x90, 0x00, 0x80}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}},
+ {3, {0xff, 0xff, 0xff}},
};
static struct idxdata tbl_init_post_alt_low1[] = {
- {0x33, "\x8c\x27\x15"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\x22\x2e"},
- {0x33, "\x90\x00\x81"}, {0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x17"},
- {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x1a"}, {0x33, "\x8c\xa4\x0a"},
- {0x33, "\x90\x00\x1d"}, {0x33, "\x8c\xa4\x0b"}, {0x33, "\x90\x00\x20"},
- {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\x81"}, {0x33, "\x8c\x24\x13"},
- {0x33, "\x90\x00\x9b"},
+ {0x33, {0x8c, 0x27, 0x15}}, {0x33, {0x90, 0x00, 0x25}},
+ {0x33, {0x8c, 0x22, 0x2e}}, {0x33, {0x90, 0x00, 0x81}},
+ {0x33, {0x8c, 0xa4, 0x08}}, {0x33, {0x90, 0x00, 0x17}},
+ {0x33, {0x8c, 0xa4, 0x09}}, {0x33, {0x90, 0x00, 0x1a}},
+ {0x33, {0x8c, 0xa4, 0x0a}}, {0x33, {0x90, 0x00, 0x1d}},
+ {0x33, {0x8c, 0xa4, 0x0b}}, {0x33, {0x90, 0x00, 0x20}},
+ {0x33, {0x8c, 0x24, 0x11}}, {0x33, {0x90, 0x00, 0x81}},
+ {0x33, {0x8c, 0x24, 0x13}}, {0x33, {0x90, 0x00, 0x9b}},
};
static struct idxdata tbl_init_post_alt_low2[] = {
- {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x03\x24"}, {0x33, "\x8c\x27\x05"},
- {0x33, "\x90\x02\x58"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
- {2, "\xff\xff\xff"},
+ {0x33, {0x8c, 0x27, 0x03}}, {0x33, {0x90, 0x03, 0x24}},
+ {0x33, {0x8c, 0x27, 0x05}}, {0x33, {0x90, 0x02, 0x58}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}},
+ {2, {0xff, 0xff, 0xff}},
};
static struct idxdata tbl_init_post_alt_low3[] = {
- {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
- {2, "\xff\xff\xff"},
- {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x20"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"},
- {0x33, "\x2e\x01\x00"}, {0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x95"}, {0x33, "\x90\x01\x00"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"},
- {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"},
- {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
+ {0x34, {0x1e, 0x8f, 0x09}}, {0x34, {0x1c, 0x01, 0x28}},
+ {0x34, {0x1e, 0x8f, 0x09}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x34, {0x1e, 0x8f, 0x09}}, {0x32, {0x14, 0x06, 0xe6}},
+ {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x01}},
+ {0x33, {0x2e, 0x01, 0x00}}, {0x34, {0x04, 0x00, 0x2a}},
+ {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0x27, 0x95}}, {0x33, {0x90, 0x01, 0x00}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x72}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x02}},
+ {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x01}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x01}},
+ {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x00}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}},
};
static struct idxdata tbl_init_post_alt_big[] = {
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
- {2, "\xff\xff\xff"},
- {0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
- {2, "\xff\xff\xff"},
- {0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x03"},
- {0x33, "\x90\x00\x05"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
- {2, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"}, {0x33, "\x8c\xa1\x20"},
- {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x30"}, {0x33, "\x90\x00\x03"},
- {0x33, "\x8c\xa1\x31"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x32"},
- {0x33, "\x90\x00\x03"}, {0x33, "\x8c\xa1\x34"}, {0x33, "\x90\x00\x03"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x2e\x01\x00"},
- {0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
- {0x33, "\x8c\x27\x97"}, {0x33, "\x90\x01\x00"},
- {51, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"},
- {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
- {51, "\xff\xff\xff"},
- {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"},
- {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
- {51, "\xff\xff\xff"},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x34, {0x1e, 0x8f, 0x09}}, {0x34, {0x1c, 0x01, 0x28}},
+ {0x34, {0x1e, 0x8f, 0x09}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x34, {0x1e, 0x8f, 0x09}}, {0x32, {0x14, 0x06, 0xe6}},
+ {0x33, {0x8c, 0xa1, 0x03}},
+ {0x33, {0x90, 0x00, 0x05}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x05}},
+ {2, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x06}},
+ {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x72}},
+ {0x33, {0x8c, 0xa1, 0x30}}, {0x33, {0x90, 0x00, 0x03}},
+ {0x33, {0x8c, 0xa1, 0x31}}, {0x33, {0x90, 0x00, 0x02}},
+ {0x33, {0x8c, 0xa1, 0x32}}, {0x33, {0x90, 0x00, 0x03}},
+ {0x33, {0x8c, 0xa1, 0x34}}, {0x33, {0x90, 0x00, 0x03}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x02}},
+ {0x33, {0x2e, 0x01, 0x00}}, {0x34, {0x04, 0x00, 0x2a}},
+ {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x01}},
+ {0x33, {0x8c, 0x27, 0x97}}, {0x33, {0x90, 0x01, 0x00}},
+ {51, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x00}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x01}},
+ {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x00}},
+ {51, {0xff, 0xff, 0xff}},
+ {0x33, {0x8c, 0xa1, 0x20}}, {0x33, {0x90, 0x00, 0x72}},
+ {0x33, {0x8c, 0xa1, 0x03}}, {0x33, {0x90, 0x00, 0x02}},
+ {0x33, {0x8c, 0xa7, 0x02}}, {0x33, {0x90, 0x00, 0x01}},
+ {51, {0xff, 0xff, 0xff}},
};
static struct idxdata tbl_init_post_alt_3B[] = {
- {0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
- {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
- {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
- {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"},
- {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"},
- {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"},
- {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"},
- {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"},
- {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"},
- {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"},
- {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"},
- {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"},
- {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"},
- {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"},
- {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"},
- {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"},
- {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"},
- {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"},
- {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"},
- {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"},
- {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"},
- {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"},
- {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"},
- {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
- {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
- {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
+ {0x32, {0x10, 0x01, 0xf8}}, {0x34, {0xce, 0x01, 0xa8}},
+ {0x34, {0xd0, 0x66, 0x33}}, {0x34, {0xd2, 0x31, 0x9a}},
+ {0x34, {0xd4, 0x94, 0x63}}, {0x34, {0xd6, 0x4b, 0x25}},
+ {0x34, {0xd8, 0x26, 0x70}}, {0x34, {0xda, 0x72, 0x4c}},
+ {0x34, {0xdc, 0xff, 0x04}}, {0x34, {0xde, 0x01, 0x5b}},
+ {0x34, {0xe6, 0x01, 0x13}}, {0x34, {0xee, 0x0b, 0xf0}},
+ {0x34, {0xf6, 0x0b, 0xa4}}, {0x35, {0x00, 0xf6, 0xe7}},
+ {0x35, {0x08, 0x0d, 0xfd}}, {0x35, {0x10, 0x25, 0x63}},
+ {0x35, {0x18, 0x35, 0x6c}}, {0x35, {0x20, 0x42, 0x7e}},
+ {0x35, {0x28, 0x19, 0x44}}, {0x35, {0x30, 0x39, 0xd4}},
+ {0x35, {0x38, 0xf5, 0xa8}}, {0x35, {0x4c, 0x07, 0x90}},
+ {0x35, {0x44, 0x07, 0xb8}}, {0x35, {0x5c, 0x06, 0x88}},
+ {0x35, {0x54, 0x07, 0xff}}, {0x34, {0xe0, 0x01, 0x52}},
+ {0x34, {0xe8, 0x00, 0xcc}}, {0x34, {0xf0, 0x0d, 0x83}},
+ {0x34, {0xf8, 0x0c, 0xb3}}, {0x35, {0x02, 0xfe, 0xba}},
+ {0x35, {0x0a, 0x04, 0xe0}}, {0x35, {0x12, 0x1c, 0x63}},
+ {0x35, {0x1a, 0x2b, 0x5a}}, {0x35, {0x22, 0x32, 0x5e}},
+ {0x35, {0x2a, 0x0d, 0x28}}, {0x35, {0x32, 0x2c, 0x02}},
+ {0x35, {0x3a, 0xf4, 0xfa}}, {0x35, {0x4e, 0x07, 0xef}},
+ {0x35, {0x46, 0x07, 0x88}}, {0x35, {0x5e, 0x07, 0xc1}},
+ {0x35, {0x56, 0x04, 0x64}}, {0x34, {0xe4, 0x01, 0x15}},
+ {0x34, {0xec, 0x00, 0x82}}, {0x34, {0xf4, 0x0c, 0xce}},
+ {0x34, {0xfc, 0x0c, 0xba}}, {0x35, {0x06, 0x1f, 0x02}},
+ {0x35, {0x0e, 0x02, 0xe3}}, {0x35, {0x16, 0x1a, 0x50}},
+ {0x35, {0x1e, 0x24, 0x39}}, {0x35, {0x26, 0x23, 0x4c}},
+ {0x35, {0x2e, 0xf9, 0x1b}}, {0x35, {0x36, 0x23, 0x19}},
+ {0x35, {0x3e, 0x12, 0x08}}, {0x35, {0x52, 0x07, 0x22}},
+ {0x35, {0x4a, 0x03, 0xd3}}, {0x35, {0x62, 0x06, 0x54}},
+ {0x35, {0x5a, 0x04, 0x5d}}, {0x34, {0xe2, 0x01, 0x04}},
+ {0x34, {0xea, 0x00, 0xa0}}, {0x34, {0xf2, 0x0c, 0xbc}},
+ {0x34, {0xfa, 0x0c, 0x5b}}, {0x35, {0x04, 0x17, 0xf2}},
+ {0x35, {0x0c, 0x02, 0x08}}, {0x35, {0x14, 0x28, 0x43}},
+ {0x35, {0x1c, 0x28, 0x62}}, {0x35, {0x24, 0x2b, 0x60}},
+ {0x35, {0x2c, 0x07, 0x33}}, {0x35, {0x34, 0x1f, 0xb0}},
+ {0x35, {0x3c, 0xed, 0xcd}}, {0x35, {0x50, 0x00, 0x06}},
+ {0x35, {0x48, 0x07, 0xff}}, {0x35, {0x60, 0x05, 0x89}},
+ {0x35, {0x58, 0x07, 0xff}}, {0x35, {0x40, 0x00, 0xa0}},
+ {0x35, {0x42, 0x00, 0x00}}, {0x32, {0x10, 0x01, 0xfc}},
+ {0x33, {0x8c, 0xa1, 0x18}}, {0x33, {0x90, 0x00, 0x3c}},
};
static u8 *dat_640 = "\xd0\x02\xd1\x08\xd2\xe1\xd3\x02\xd4\x10\xd5\x81";
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
index ea05f678b559..9623b6218214 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
@@ -2910,7 +2910,7 @@ static void pvr2_subdev_update(struct pvr2_hdw *hdw)
v4l2_std_id vs;
vs = hdw->std_mask_cur;
v4l2_device_call_all(&hdw->v4l2_dev, 0,
- core, s_std, vs);
+ video, s_std, vs);
pvr2_hdw_cx25840_vbi_hack(hdw);
}
hdw->tuner_signal_stale = !0;
diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c
index 84a6720b1d00..a73b0bced96f 100644
--- a/drivers/media/usb/pwc/pwc-if.c
+++ b/drivers/media/usb/pwc/pwc-if.c
@@ -681,12 +681,11 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
return r;
}
-static int stop_streaming(struct vb2_queue *vq)
+static void stop_streaming(struct vb2_queue *vq)
{
struct pwc_device *pdev = vb2_get_drv_priv(vq);
- if (mutex_lock_interruptible(&pdev->v4l2_lock))
- return -ERESTARTSYS;
+ mutex_lock(&pdev->v4l2_lock);
if (pdev->udev) {
pwc_set_leds(pdev, 0, 0);
pwc_camera_power(pdev, 0);
@@ -695,8 +694,6 @@ static int stop_streaming(struct vb2_queue *vq)
pwc_cleanup_queued_bufs(pdev);
mutex_unlock(&pdev->v4l2_lock);
-
- return 0;
}
static struct vb2_ops pwc_vb_queue_ops = {
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index 1d4ba2b80490..a44466bc7b86 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -714,7 +714,7 @@ static void buffer_queue(struct vb2_buffer *vb)
}
static int start_streaming(struct vb2_queue *vq, unsigned int count);
-static int stop_streaming(struct vb2_queue *vq);
+static void stop_streaming(struct vb2_queue *vq);
static struct vb2_ops s2255_video_qops = {
.queue_setup = queue_setup,
@@ -1109,7 +1109,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
}
/* abort streaming and wait for last buffer */
-static int stop_streaming(struct vb2_queue *vq)
+static void stop_streaming(struct vb2_queue *vq)
{
struct s2255_vc *vc = vb2_get_drv_priv(vq);
struct s2255_buffer *buf, *node;
@@ -1123,7 +1123,6 @@ static int stop_streaming(struct vb2_queue *vq)
buf, buf->vb.v4l2_buf.index);
}
spin_unlock_irqrestore(&vc->qlock, flags);
- return 0;
}
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id i)
@@ -1522,7 +1521,7 @@ static void s2255_destroy(struct s2255_dev *dev)
/* board shutdown stops the read pipe if it is running */
s2255_board_shutdown(dev);
/* make sure firmware still not trying to load */
- del_timer(&dev->timer); /* only started in .probe and .open */
+ del_timer_sync(&dev->timer); /* only started in .probe and .open */
if (dev->fw_data->fw_urb) {
usb_kill_urb(dev->fw_data->fw_urb);
usb_free_urb(dev->fw_data->fw_urb);
@@ -2243,7 +2242,7 @@ static int s2255_probe(struct usb_interface *interface,
dev->cmdbuf = kzalloc(S2255_CMDBUF_SIZE, GFP_KERNEL);
if (dev->cmdbuf == NULL) {
s2255_dev_err(&interface->dev, "out of memory\n");
- return -ENOMEM;
+ goto errorFWDATA1;
}
atomic_set(&dev->num_channels, 0);
@@ -2352,7 +2351,7 @@ errorREQFW:
errorFWDATA2:
usb_free_urb(dev->fw_data->fw_urb);
errorFWURB:
- del_timer(&dev->timer);
+ del_timer_sync(&dev->timer);
errorEP:
usb_put_dev(dev->udev);
errorUDEV:
diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c
index 34a26e0cfe77..03504dcf3c52 100644
--- a/drivers/media/usb/stk1160/stk1160-core.c
+++ b/drivers/media/usb/stk1160/stk1160-core.c
@@ -67,17 +67,25 @@ int stk1160_read_reg(struct stk1160 *dev, u16 reg, u8 *value)
{
int ret;
int pipe = usb_rcvctrlpipe(dev->udev, 0);
+ u8 *buf;
*value = 0;
+
+ buf = kmalloc(sizeof(u8), GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
ret = usb_control_msg(dev->udev, pipe, 0x00,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0x00, reg, value, sizeof(u8), HZ);
+ 0x00, reg, buf, sizeof(u8), HZ);
if (ret < 0) {
stk1160_err("read failed on reg 0x%x (%d)\n",
reg, ret);
+ kfree(buf);
return ret;
}
+ *value = *buf;
+ kfree(buf);
return 0;
}
diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c
index 37bc00f418f1..5461341a31cb 100644
--- a/drivers/media/usb/stk1160/stk1160-v4l.c
+++ b/drivers/media/usb/stk1160/stk1160-v4l.c
@@ -406,7 +406,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
stk1160_set_std(dev);
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std,
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std,
dev->norm);
return 0;
@@ -583,10 +583,10 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
}
/* abort streaming and wait for last buffer */
-static int stop_streaming(struct vb2_queue *vq)
+static void stop_streaming(struct vb2_queue *vq)
{
struct stk1160 *dev = vb2_get_drv_priv(vq);
- return stk1160_stop_streaming(dev);
+ stk1160_stop_streaming(dev);
}
static struct vb2_ops stk1160_video_qops = {
@@ -682,7 +682,7 @@ int stk1160_video_register(struct stk1160 *dev)
dev->fmt = &format[0];
stk1160_set_std(dev);
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std,
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std,
dev->norm);
video_set_drvdata(&dev->vdev, dev);
diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h
index 05b05b160e1e..abdea484c998 100644
--- a/drivers/media/usb/stk1160/stk1160.h
+++ b/drivers/media/usb/stk1160/stk1160.h
@@ -143,7 +143,6 @@ struct stk1160 {
int num_alt;
struct stk1160_isoc_ctl isoc_ctl;
- char urb_buf[255]; /* urb control msg buffer */
/* frame properties */
int width; /* current frame width */
diff --git a/drivers/media/usb/tm6000/tm6000-cards.c b/drivers/media/usb/tm6000/tm6000-cards.c
index 1ccaaddaa307..2e8c3afe4ec4 100644
--- a/drivers/media/usb/tm6000/tm6000-cards.c
+++ b/drivers/media/usb/tm6000/tm6000-cards.c
@@ -1120,7 +1120,7 @@ static int tm6000_init_dev(struct tm6000_core *dev)
tm6000_config_tuner(dev);
/* Set video standard */
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm);
/* Set tuner frequency - also loads firmware on xc2028/xc3028 */
f.tuner = 0;
diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c
index cc1aa14996ff..e6b3d5d83d43 100644
--- a/drivers/media/usb/tm6000/tm6000-video.c
+++ b/drivers/media/usb/tm6000/tm6000-video.c
@@ -1071,7 +1071,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
if (rc < 0)
return rc;
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm);
return 0;
}
diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c
index 20365bd69d05..2967e808408b 100644
--- a/drivers/media/usb/usbtv/usbtv-video.c
+++ b/drivers/media/usb/usbtv/usbtv-video.c
@@ -634,15 +634,12 @@ static int usbtv_start_streaming(struct vb2_queue *vq, unsigned int count)
return usbtv_start(usbtv);
}
-static int usbtv_stop_streaming(struct vb2_queue *vq)
+static void usbtv_stop_streaming(struct vb2_queue *vq)
{
struct usbtv *usbtv = vb2_get_drv_priv(vq);
- if (usbtv->udev == NULL)
- return -ENODEV;
-
- usbtv_stop(usbtv);
- return 0;
+ if (usbtv->udev)
+ usbtv_stop(usbtv);
}
static struct vb2_ops usbtv_vb2_ops = {
diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c
index 5c9e3123ad2e..68bc9615660e 100644
--- a/drivers/media/usb/usbvision/usbvision-video.c
+++ b/drivers/media/usb/usbvision/usbvision-video.c
@@ -597,7 +597,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
usbvision->tvnorm_id = id;
- call_all(usbvision, core, s_std, usbvision->tvnorm_id);
+ call_all(usbvision, video, s_std, usbvision->tvnorm_id);
/* propagate the change to the decoder */
usbvision_muxsel(usbvision, usbvision->ctl_input);
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index 8d52baf5952b..9144a2f3ed82 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -361,6 +361,14 @@ static int uvc_commit_video(struct uvc_streaming *stream,
* Clocks and timestamps
*/
+static inline void uvc_video_get_ts(struct timespec *ts)
+{
+ if (uvc_clock_param == CLOCK_MONOTONIC)
+ ktime_get_ts(ts);
+ else
+ ktime_get_real_ts(ts);
+}
+
static void
uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
const __u8 *data, int len)
@@ -420,7 +428,7 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
stream->clock.last_sof = dev_sof;
host_sof = usb_get_current_frame_number(stream->dev->udev);
- ktime_get_ts(&ts);
+ uvc_video_get_ts(&ts);
/* The UVC specification allows device implementations that can't obtain
* the USB frame number to keep their own frame counters as long as they
@@ -1011,10 +1019,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
return -ENODATA;
}
- if (uvc_clock_param == CLOCK_MONOTONIC)
- ktime_get_ts(&ts);
- else
- ktime_get_real_ts(&ts);
+ uvc_video_get_ts(&ts);
buf->buf.v4l2_buf.sequence = stream->sequence;
buf->buf.v4l2_buf.timestamp.tv_sec = ts.tv_sec;
@@ -1133,6 +1138,17 @@ static int uvc_video_encode_data(struct uvc_streaming *stream,
*/
/*
+ * Set error flag for incomplete buffer.
+ */
+static void uvc_video_validate_buffer(const struct uvc_streaming *stream,
+ struct uvc_buffer *buf)
+{
+ if (buf->length != buf->bytesused &&
+ !(stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED))
+ buf->error = 1;
+}
+
+/*
* Completion handler for video URBs.
*/
static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
@@ -1156,9 +1172,11 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
do {
ret = uvc_video_decode_start(stream, buf, mem,
urb->iso_frame_desc[i].actual_length);
- if (ret == -EAGAIN)
+ if (ret == -EAGAIN) {
+ uvc_video_validate_buffer(stream, buf);
buf = uvc_queue_next_buffer(&stream->queue,
buf);
+ }
} while (ret == -EAGAIN);
if (ret < 0)
@@ -1173,11 +1191,7 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
urb->iso_frame_desc[i].actual_length);
if (buf->state == UVC_BUF_STATE_READY) {
- if (buf->length != buf->bytesused &&
- !(stream->cur_format->flags &
- UVC_FMT_FLAG_COMPRESSED))
- buf->error = 1;
-
+ uvc_video_validate_buffer(stream, buf);
buf = uvc_queue_next_buffer(&stream->queue, buf);
}
}
diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
index 2189bfb2e828..9ca0f8d59a14 100644
--- a/drivers/media/v4l2-core/Kconfig
+++ b/drivers/media/v4l2-core/Kconfig
@@ -83,3 +83,7 @@ config VIDEOBUF2_DMA_SG
#depends on HAS_DMA
select VIDEOBUF2_CORE
select VIDEOBUF2_MEMOPS
+
+config VIDEOBUF2_DVB
+ tristate
+ select VIDEOBUF2_CORE
diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile
index c6ae7bad951e..63d29f27538c 100644
--- a/drivers/media/v4l2-core/Makefile
+++ b/drivers/media/v4l2-core/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_VIDEOBUF2_MEMOPS) += videobuf2-memops.o
obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o
obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o
obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o
+obj-$(CONFIG_VIDEOBUF2_DVB) += videobuf2-dvb.o
ccflags-y += -I$(srctree)/drivers/media/dvb-core
ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c
index 20c09229a08e..06c18ba16fa0 100644
--- a/drivers/media/v4l2-core/tuner-core.c
+++ b/drivers/media/v4l2-core/tuner-core.c
@@ -1301,7 +1301,6 @@ static int tuner_command(struct i2c_client *client, unsigned cmd, void *arg)
static const struct v4l2_subdev_core_ops tuner_core_ops = {
.log_status = tuner_log_status,
- .s_std = tuner_s_std,
.s_power = tuner_s_power,
};
@@ -1315,9 +1314,14 @@ static const struct v4l2_subdev_tuner_ops tuner_tuner_ops = {
.s_config = tuner_s_config,
};
+static const struct v4l2_subdev_video_ops tuner_video_ops = {
+ .s_std = tuner_s_std,
+};
+
static const struct v4l2_subdev_ops tuner_ops = {
.core = &tuner_core_ops,
.tuner = &tuner_tuner_ops,
+ .video = &tuner_video_ops,
};
/*
diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c
index 02d1b6327117..015f92aab44a 100644
--- a/drivers/media/v4l2-core/v4l2-device.c
+++ b/drivers/media/v4l2-core/v4l2-device.c
@@ -158,7 +158,17 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
/* Warn if we apparently re-register a subdev */
WARN_ON(sd->v4l2_dev != NULL);
- if (!try_module_get(sd->owner))
+ /*
+ * The reason to acquire the module here is to avoid unloading
+ * a module of sub-device which is registered to a media
+ * device. To make it possible to unload modules for media
+ * devices that also register sub-devices, do not
+ * try_module_get() such sub-device owners.
+ */
+ sd->owner_v4l2_dev = v4l2_dev->dev && v4l2_dev->dev->driver &&
+ sd->owner == v4l2_dev->dev->driver->owner;
+
+ if (!sd->owner_v4l2_dev && !try_module_get(sd->owner))
return -ENODEV;
sd->v4l2_dev = v4l2_dev;
@@ -192,7 +202,8 @@ error_unregister:
if (sd->internal_ops && sd->internal_ops->unregistered)
sd->internal_ops->unregistered(sd);
error_module:
- module_put(sd->owner);
+ if (!sd->owner_v4l2_dev)
+ module_put(sd->owner);
sd->v4l2_dev = NULL;
return err;
}
@@ -280,6 +291,7 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
}
#endif
video_unregister_device(sd->devnode);
- module_put(sd->owner);
+ if (!sd->owner_v4l2_dev)
+ module_put(sd->owner);
}
EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev);
diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c
index 48b20dfcc4d0..4ae54caadd03 100644
--- a/drivers/media/v4l2-core/v4l2-dv-timings.c
+++ b/drivers/media/v4l2-core/v4l2-dv-timings.c
@@ -131,6 +131,17 @@ const struct v4l2_dv_timings v4l2_dv_timings_presets[] = {
V4L2_DV_BT_DMT_2560X1600P75,
V4L2_DV_BT_DMT_2560X1600P85,
V4L2_DV_BT_DMT_2560X1600P120_RB,
+ V4L2_DV_BT_CEA_3840X2160P24,
+ V4L2_DV_BT_CEA_3840X2160P25,
+ V4L2_DV_BT_CEA_3840X2160P30,
+ V4L2_DV_BT_CEA_3840X2160P50,
+ V4L2_DV_BT_CEA_3840X2160P60,
+ V4L2_DV_BT_CEA_4096X2160P24,
+ V4L2_DV_BT_CEA_4096X2160P25,
+ V4L2_DV_BT_CEA_4096X2160P30,
+ V4L2_DV_BT_CEA_4096X2160P50,
+ V4L2_DV_BT_DMT_4096X2160P59_94_RB,
+ V4L2_DV_BT_CEA_4096X2160P60,
{ }
};
EXPORT_SYMBOL_GPL(v4l2_dv_timings_presets);
diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c
index 86dcb5483c42..8761aab99de9 100644
--- a/drivers/media/v4l2-core/v4l2-event.c
+++ b/drivers/media/v4l2-core/v4l2-event.c
@@ -318,3 +318,39 @@ int v4l2_event_subdev_unsubscribe(struct v4l2_subdev *sd, struct v4l2_fh *fh,
return v4l2_event_unsubscribe(fh, sub);
}
EXPORT_SYMBOL_GPL(v4l2_event_subdev_unsubscribe);
+
+static void v4l2_event_src_replace(struct v4l2_event *old,
+ const struct v4l2_event *new)
+{
+ u32 old_changes = old->u.src_change.changes;
+
+ old->u.src_change = new->u.src_change;
+ old->u.src_change.changes |= old_changes;
+}
+
+static void v4l2_event_src_merge(const struct v4l2_event *old,
+ struct v4l2_event *new)
+{
+ new->u.src_change.changes |= old->u.src_change.changes;
+}
+
+static const struct v4l2_subscribed_event_ops v4l2_event_src_ch_ops = {
+ .replace = v4l2_event_src_replace,
+ .merge = v4l2_event_src_merge,
+};
+
+int v4l2_src_change_event_subscribe(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
+ if (sub->type == V4L2_EVENT_SOURCE_CHANGE)
+ return v4l2_event_subscribe(fh, sub, 0, &v4l2_event_src_ch_ops);
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(v4l2_src_change_event_subscribe);
+
+int v4l2_src_change_event_subdev_subscribe(struct v4l2_subdev *sd,
+ struct v4l2_fh *fh, struct v4l2_event_subscription *sub)
+{
+ return v4l2_src_change_event_subscribe(fh, sub);
+}
+EXPORT_SYMBOL_GPL(v4l2_src_change_event_subdev_subscribe);
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index d9113cc71c77..16bffd851bf9 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -562,7 +562,7 @@ static void v4l_print_cropcap(const void *arg, bool write_only)
const struct v4l2_cropcap *p = arg;
pr_cont("type=%s, bounds wxh=%dx%d, x,y=%d,%d, "
- "defrect wxh=%dx%d, x,y=%d,%d\n, "
+ "defrect wxh=%dx%d, x,y=%d,%d, "
"pixelaspect %d/%d\n",
prt_names(p->type, v4l2_type_names),
p->bounds.width, p->bounds.height,
@@ -2260,7 +2260,7 @@ done:
}
static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
- void * __user *user_ptr, void ***kernel_ptr)
+ void __user **user_ptr, void ***kernel_ptr)
{
int ret = 0;
@@ -2277,7 +2277,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
break;
}
*user_ptr = (void __user *)buf->m.planes;
- *kernel_ptr = (void *)&buf->m.planes;
+ *kernel_ptr = (void **)&buf->m.planes;
*array_size = sizeof(struct v4l2_plane) * buf->length;
ret = 1;
}
@@ -2294,7 +2294,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
break;
}
*user_ptr = (void __user *)edid->edid;
- *kernel_ptr = (void *)&edid->edid;
+ *kernel_ptr = (void **)&edid->edid;
*array_size = edid->blocks * 128;
ret = 1;
}
@@ -2312,7 +2312,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
break;
}
*user_ptr = (void __user *)ctrls->controls;
- *kernel_ptr = (void *)&ctrls->controls;
+ *kernel_ptr = (void **)&ctrls->controls;
*array_size = sizeof(struct v4l2_ext_control)
* ctrls->count;
ret = 1;
@@ -2412,7 +2412,7 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
}
if (has_array_args) {
- *kernel_ptr = user_ptr;
+ *kernel_ptr = (void __force *)user_ptr;
if (copy_to_user(user_ptr, mbuf, array_size))
err = -EFAULT;
goto out_array_args;
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index aea84ac5688a..058c1a6e8392 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -305,11 +305,23 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
fse);
}
- case VIDIOC_SUBDEV_G_FRAME_INTERVAL:
+ case VIDIOC_SUBDEV_G_FRAME_INTERVAL: {
+ struct v4l2_subdev_frame_interval *fi = arg;
+
+ if (fi->pad >= sd->entity.num_pads)
+ return -EINVAL;
+
return v4l2_subdev_call(sd, video, g_frame_interval, arg);
+ }
+
+ case VIDIOC_SUBDEV_S_FRAME_INTERVAL: {
+ struct v4l2_subdev_frame_interval *fi = arg;
+
+ if (fi->pad >= sd->entity.num_pads)
+ return -EINVAL;
- case VIDIOC_SUBDEV_S_FRAME_INTERVAL:
return v4l2_subdev_call(sd, video, s_frame_interval, arg);
+ }
case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: {
struct v4l2_subdev_frame_interval_enum *fie = arg;
@@ -349,11 +361,54 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
sd, pad, set_selection, subdev_fh, sel);
}
- case VIDIOC_G_EDID:
- return v4l2_subdev_call(sd, pad, get_edid, arg);
+ case VIDIOC_G_EDID: {
+ struct v4l2_subdev_edid *edid = arg;
+
+ if (edid->pad >= sd->entity.num_pads)
+ return -EINVAL;
+ if (edid->blocks && edid->edid == NULL)
+ return -EINVAL;
+
+ return v4l2_subdev_call(sd, pad, get_edid, edid);
+ }
+
+ case VIDIOC_S_EDID: {
+ struct v4l2_subdev_edid *edid = arg;
+
+ if (edid->pad >= sd->entity.num_pads)
+ return -EINVAL;
+ if (edid->blocks && edid->edid == NULL)
+ return -EINVAL;
+
+ return v4l2_subdev_call(sd, pad, set_edid, edid);
+ }
+
+ case VIDIOC_SUBDEV_DV_TIMINGS_CAP: {
+ struct v4l2_dv_timings_cap *cap = arg;
+
+ if (cap->pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ return v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
+ }
+
+ case VIDIOC_SUBDEV_ENUM_DV_TIMINGS: {
+ struct v4l2_enum_dv_timings *dvt = arg;
+
+ if (dvt->pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ return v4l2_subdev_call(sd, pad, enum_dv_timings, dvt);
+ }
+
+ case VIDIOC_SUBDEV_QUERY_DV_TIMINGS:
+ return v4l2_subdev_call(sd, video, query_dv_timings, arg);
+
+ case VIDIOC_SUBDEV_G_DV_TIMINGS:
+ return v4l2_subdev_call(sd, video, g_dv_timings, arg);
- case VIDIOC_S_EDID:
- return v4l2_subdev_call(sd, pad, set_edid, arg);
+ case VIDIOC_SUBDEV_S_DV_TIMINGS:
+ return v4l2_subdev_call(sd, video, s_dv_timings, arg);
#endif
default:
return v4l2_subdev_call(sd, core, ioctl, cmd, arg);
diff --git a/drivers/media/v4l2-core/videobuf-dma-contig.c b/drivers/media/v4l2-core/videobuf-dma-contig.c
index 7e6b209b7002..bf80f0f7dfb8 100644
--- a/drivers/media/v4l2-core/videobuf-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf-dma-contig.c
@@ -305,7 +305,7 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
/* Try to remap memory */
size = vma->vm_end - vma->vm_start;
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
- retval = vm_iomap_memory(vma, vma->vm_start, size);
+ retval = vm_iomap_memory(vma, mem->dma_handle, size);
if (retval) {
dev_err(q->dev, "mmap: remap failed with error %d. ",
retval);
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index f9059bb73840..349e659d75fb 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -6,6 +6,9 @@
* Author: Pawel Osciak <pawel@osciak.com>
* Marek Szyprowski <m.szyprowski@samsung.com>
*
+ * The vb2_thread implementation was based on code from videobuf-dvb.c:
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]
+ *
* 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.
@@ -18,76 +21,154 @@
#include <linux/poll.h>
#include <linux/slab.h>
#include <linux/sched.h>
+#include <linux/freezer.h>
+#include <linux/kthread.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
+#include <media/v4l2-common.h>
#include <media/videobuf2-core.h>
static int debug;
module_param(debug, int, 0644);
-#define dprintk(level, fmt, arg...) \
- do { \
- if (debug >= level) \
- printk(KERN_DEBUG "vb2: " fmt, ## arg); \
+#define dprintk(level, fmt, arg...) \
+ do { \
+ if (debug >= level) \
+ pr_debug("vb2: %s: " fmt, __func__, ## arg); \
} while (0)
#ifdef CONFIG_VIDEO_ADV_DEBUG
/*
- * If advanced debugging is on, then count how often each op is called,
- * which can either be per-buffer or per-queue.
+ * If advanced debugging is on, then count how often each op is called
+ * successfully, which can either be per-buffer or per-queue.
*
- * If the op failed then the 'fail_' variant is called to decrease the
- * counter. That makes it easy to check that the 'init' and 'cleanup'
+ * This makes it easy to check that the 'init' and 'cleanup'
* (and variations thereof) stay balanced.
*/
+#define log_memop(vb, op) \
+ dprintk(2, "call_memop(%p, %d, %s)%s\n", \
+ (vb)->vb2_queue, (vb)->v4l2_buf.index, #op, \
+ (vb)->vb2_queue->mem_ops->op ? "" : " (nop)")
+
#define call_memop(vb, op, args...) \
({ \
struct vb2_queue *_q = (vb)->vb2_queue; \
- dprintk(2, "call_memop(%p, %d, %s)%s\n", \
- _q, (vb)->v4l2_buf.index, #op, \
- _q->mem_ops->op ? "" : " (nop)"); \
+ int err; \
+ \
+ log_memop(vb, op); \
+ err = _q->mem_ops->op ? _q->mem_ops->op(args) : 0; \
+ if (!err) \
+ (vb)->cnt_mem_ ## op++; \
+ err; \
+})
+
+#define call_ptr_memop(vb, op, args...) \
+({ \
+ struct vb2_queue *_q = (vb)->vb2_queue; \
+ void *ptr; \
+ \
+ log_memop(vb, op); \
+ ptr = _q->mem_ops->op ? _q->mem_ops->op(args) : NULL; \
+ if (!IS_ERR_OR_NULL(ptr)) \
+ (vb)->cnt_mem_ ## op++; \
+ ptr; \
+})
+
+#define call_void_memop(vb, op, args...) \
+({ \
+ struct vb2_queue *_q = (vb)->vb2_queue; \
+ \
+ log_memop(vb, op); \
+ if (_q->mem_ops->op) \
+ _q->mem_ops->op(args); \
(vb)->cnt_mem_ ## op++; \
- _q->mem_ops->op ? _q->mem_ops->op(args) : 0; \
})
-#define fail_memop(vb, op) ((vb)->cnt_mem_ ## op--)
+
+#define log_qop(q, op) \
+ dprintk(2, "call_qop(%p, %s)%s\n", q, #op, \
+ (q)->ops->op ? "" : " (nop)")
#define call_qop(q, op, args...) \
({ \
- dprintk(2, "call_qop(%p, %s)%s\n", q, #op, \
- (q)->ops->op ? "" : " (nop)"); \
+ int err; \
+ \
+ log_qop(q, op); \
+ err = (q)->ops->op ? (q)->ops->op(args) : 0; \
+ if (!err) \
+ (q)->cnt_ ## op++; \
+ err; \
+})
+
+#define call_void_qop(q, op, args...) \
+({ \
+ log_qop(q, op); \
+ if ((q)->ops->op) \
+ (q)->ops->op(args); \
(q)->cnt_ ## op++; \
- (q)->ops->op ? (q)->ops->op(args) : 0; \
})
-#define fail_qop(q, op) ((q)->cnt_ ## op--)
+
+#define log_vb_qop(vb, op, args...) \
+ dprintk(2, "call_vb_qop(%p, %d, %s)%s\n", \
+ (vb)->vb2_queue, (vb)->v4l2_buf.index, #op, \
+ (vb)->vb2_queue->ops->op ? "" : " (nop)")
#define call_vb_qop(vb, op, args...) \
({ \
- struct vb2_queue *_q = (vb)->vb2_queue; \
- dprintk(2, "call_vb_qop(%p, %d, %s)%s\n", \
- _q, (vb)->v4l2_buf.index, #op, \
- _q->ops->op ? "" : " (nop)"); \
+ int err; \
+ \
+ log_vb_qop(vb, op); \
+ err = (vb)->vb2_queue->ops->op ? \
+ (vb)->vb2_queue->ops->op(args) : 0; \
+ if (!err) \
+ (vb)->cnt_ ## op++; \
+ err; \
+})
+
+#define call_void_vb_qop(vb, op, args...) \
+({ \
+ log_vb_qop(vb, op); \
+ if ((vb)->vb2_queue->ops->op) \
+ (vb)->vb2_queue->ops->op(args); \
(vb)->cnt_ ## op++; \
- _q->ops->op ? _q->ops->op(args) : 0; \
})
-#define fail_vb_qop(vb, op) ((vb)->cnt_ ## op--)
#else
#define call_memop(vb, op, args...) \
- ((vb)->vb2_queue->mem_ops->op ? (vb)->vb2_queue->mem_ops->op(args) : 0)
-#define fail_memop(vb, op)
+ ((vb)->vb2_queue->mem_ops->op ? \
+ (vb)->vb2_queue->mem_ops->op(args) : 0)
+
+#define call_ptr_memop(vb, op, args...) \
+ ((vb)->vb2_queue->mem_ops->op ? \
+ (vb)->vb2_queue->mem_ops->op(args) : NULL)
+
+#define call_void_memop(vb, op, args...) \
+ do { \
+ if ((vb)->vb2_queue->mem_ops->op) \
+ (vb)->vb2_queue->mem_ops->op(args); \
+ } while (0)
#define call_qop(q, op, args...) \
((q)->ops->op ? (q)->ops->op(args) : 0)
-#define fail_qop(q, op)
+
+#define call_void_qop(q, op, args...) \
+ do { \
+ if ((q)->ops->op) \
+ (q)->ops->op(args); \
+ } while (0)
#define call_vb_qop(vb, op, args...) \
((vb)->vb2_queue->ops->op ? (vb)->vb2_queue->ops->op(args) : 0)
-#define fail_vb_qop(vb, op)
+
+#define call_void_vb_qop(vb, op, args...) \
+ do { \
+ if ((vb)->vb2_queue->ops->op) \
+ (vb)->vb2_queue->ops->op(args); \
+ } while (0)
#endif
@@ -118,7 +199,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
for (plane = 0; plane < vb->num_planes; ++plane) {
unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]);
- mem_priv = call_memop(vb, alloc, q->alloc_ctx[plane],
+ mem_priv = call_ptr_memop(vb, alloc, q->alloc_ctx[plane],
size, q->gfp_flags);
if (IS_ERR_OR_NULL(mem_priv))
goto free;
@@ -130,10 +211,9 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
return 0;
free:
- fail_memop(vb, alloc);
/* Free already allocated memory if one of the allocations failed */
for (; plane > 0; --plane) {
- call_memop(vb, put, vb->planes[plane - 1].mem_priv);
+ call_void_memop(vb, put, vb->planes[plane - 1].mem_priv);
vb->planes[plane - 1].mem_priv = NULL;
}
@@ -148,9 +228,9 @@ static void __vb2_buf_mem_free(struct vb2_buffer *vb)
unsigned int plane;
for (plane = 0; plane < vb->num_planes; ++plane) {
- call_memop(vb, put, vb->planes[plane].mem_priv);
+ call_void_memop(vb, put, vb->planes[plane].mem_priv);
vb->planes[plane].mem_priv = NULL;
- dprintk(3, "Freed plane %d of buffer %d\n", plane,
+ dprintk(3, "freed plane %d of buffer %d\n", plane,
vb->v4l2_buf.index);
}
}
@@ -165,7 +245,7 @@ static void __vb2_buf_userptr_put(struct vb2_buffer *vb)
for (plane = 0; plane < vb->num_planes; ++plane) {
if (vb->planes[plane].mem_priv)
- call_memop(vb, put_userptr, vb->planes[plane].mem_priv);
+ call_void_memop(vb, put_userptr, vb->planes[plane].mem_priv);
vb->planes[plane].mem_priv = NULL;
}
}
@@ -180,9 +260,9 @@ static void __vb2_plane_dmabuf_put(struct vb2_buffer *vb, struct vb2_plane *p)
return;
if (p->dbuf_mapped)
- call_memop(vb, unmap_dmabuf, p->mem_priv);
+ call_void_memop(vb, unmap_dmabuf, p->mem_priv);
- call_memop(vb, detach_dmabuf, p->mem_priv);
+ call_void_memop(vb, detach_dmabuf, p->mem_priv);
dma_buf_put(p->dbuf);
memset(p, 0, sizeof(*p));
}
@@ -245,7 +325,7 @@ static void __setup_offsets(struct vb2_queue *q, unsigned int n)
for (plane = 0; plane < vb->num_planes; ++plane) {
vb->v4l2_planes[plane].m.mem_offset = off;
- dprintk(3, "Buffer %d, plane %d offset 0x%08lx\n",
+ dprintk(3, "buffer %d, plane %d offset 0x%08lx\n",
buffer, plane, off);
off += vb->v4l2_planes[plane].length;
@@ -272,7 +352,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory,
/* Allocate videobuf buffer structures */
vb = kzalloc(q->buf_struct_size, GFP_KERNEL);
if (!vb) {
- dprintk(1, "Memory alloc for buffer struct failed\n");
+ dprintk(1, "memory alloc for buffer struct failed\n");
break;
}
@@ -291,7 +371,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory,
if (memory == V4L2_MEMORY_MMAP) {
ret = __vb2_buf_mem_alloc(vb);
if (ret) {
- dprintk(1, "Failed allocating memory for "
+ dprintk(1, "failed allocating memory for "
"buffer %d\n", buffer);
kfree(vb);
break;
@@ -303,9 +383,8 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory,
*/
ret = call_vb_qop(vb, buf_init, vb);
if (ret) {
- dprintk(1, "Buffer %d %p initialization"
+ dprintk(1, "buffer %d %p initialization"
" failed\n", buffer, vb);
- fail_vb_qop(vb, buf_init);
__vb2_buf_mem_free(vb);
kfree(vb);
break;
@@ -319,7 +398,7 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum v4l2_memory memory,
if (memory == V4L2_MEMORY_MMAP)
__setup_offsets(q, buffer);
- dprintk(1, "Allocated %d buffers, %d plane(s) each\n",
+ dprintk(1, "allocated %d buffers, %d plane(s) each\n",
buffer, num_planes);
return buffer;
@@ -371,7 +450,7 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
if (q->bufs[buffer] == NULL)
continue;
if (q->bufs[buffer]->state == VB2_BUF_STATE_PREPARING) {
- dprintk(1, "reqbufs: preparing buffers, cannot free\n");
+ dprintk(1, "preparing buffers, cannot free\n");
return -EAGAIN;
}
}
@@ -382,7 +461,7 @@ static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
struct vb2_buffer *vb = q->bufs[buffer];
if (vb && vb->planes[0].mem_priv)
- call_vb_qop(vb, buf_cleanup, vb);
+ call_void_vb_qop(vb, buf_cleanup, vb);
}
/* Release video buffer memory */
@@ -476,13 +555,13 @@ static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer
/* Is memory for copying plane information present? */
if (NULL == b->m.planes) {
- dprintk(1, "Multi-planar buffer passed but "
+ dprintk(1, "multi-planar buffer passed but "
"planes array not provided\n");
return -EINVAL;
}
if (b->length < vb->num_planes || b->length > VIDEO_MAX_PLANES) {
- dprintk(1, "Incorrect planes array length, "
+ dprintk(1, "incorrect planes array length, "
"expected %d, got %d\n", vb->num_planes, b->length);
return -EINVAL;
}
@@ -656,12 +735,12 @@ int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b)
int ret;
if (b->type != q->type) {
- dprintk(1, "querybuf: wrong buffer type\n");
+ dprintk(1, "wrong buffer type\n");
return -EINVAL;
}
if (b->index >= q->num_buffers) {
- dprintk(1, "querybuf: buffer index out of range\n");
+ dprintk(1, "buffer index out of range\n");
return -EINVAL;
}
vb = q->bufs[b->index];
@@ -721,12 +800,12 @@ static int __verify_memory_type(struct vb2_queue *q,
{
if (memory != V4L2_MEMORY_MMAP && memory != V4L2_MEMORY_USERPTR &&
memory != V4L2_MEMORY_DMABUF) {
- dprintk(1, "reqbufs: unsupported memory type\n");
+ dprintk(1, "unsupported memory type\n");
return -EINVAL;
}
if (type != q->type) {
- dprintk(1, "reqbufs: requested type is incorrect\n");
+ dprintk(1, "requested type is incorrect\n");
return -EINVAL;
}
@@ -735,17 +814,17 @@ static int __verify_memory_type(struct vb2_queue *q,
* are available.
*/
if (memory == V4L2_MEMORY_MMAP && __verify_mmap_ops(q)) {
- dprintk(1, "reqbufs: MMAP for current setup unsupported\n");
+ dprintk(1, "MMAP for current setup unsupported\n");
return -EINVAL;
}
if (memory == V4L2_MEMORY_USERPTR && __verify_userptr_ops(q)) {
- dprintk(1, "reqbufs: USERPTR for current setup unsupported\n");
+ dprintk(1, "USERPTR for current setup unsupported\n");
return -EINVAL;
}
if (memory == V4L2_MEMORY_DMABUF && __verify_dmabuf_ops(q)) {
- dprintk(1, "reqbufs: DMABUF for current setup unsupported\n");
+ dprintk(1, "DMABUF for current setup unsupported\n");
return -EINVAL;
}
@@ -754,8 +833,8 @@ static int __verify_memory_type(struct vb2_queue *q,
* create_bufs is called with count == 0, but count == 0 should still
* do the memory and type validation.
*/
- if (q->fileio) {
- dprintk(1, "reqbufs: file io in progress\n");
+ if (vb2_fileio_is_active(q)) {
+ dprintk(1, "file io in progress\n");
return -EBUSY;
}
return 0;
@@ -790,7 +869,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
int ret;
if (q->streaming) {
- dprintk(1, "reqbufs: streaming active\n");
+ dprintk(1, "streaming active\n");
return -EBUSY;
}
@@ -800,7 +879,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
* are not in use and can be freed.
*/
if (q->memory == V4L2_MEMORY_MMAP && __buffers_in_use(q)) {
- dprintk(1, "reqbufs: memory in use, cannot free\n");
+ dprintk(1, "memory in use, cannot free\n");
return -EBUSY;
}
@@ -826,7 +905,7 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
* Make sure the requested values and current defaults are sane.
*/
num_buffers = min_t(unsigned int, req->count, VIDEO_MAX_FRAME);
- num_buffers = max_t(unsigned int, req->count, q->min_buffers_needed);
+ num_buffers = max_t(unsigned int, num_buffers, q->min_buffers_needed);
memset(q->plane_sizes, 0, sizeof(q->plane_sizes));
memset(q->alloc_ctx, 0, sizeof(q->alloc_ctx));
q->memory = req->memory;
@@ -837,15 +916,13 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
*/
ret = call_qop(q, queue_setup, q, NULL, &num_buffers, &num_planes,
q->plane_sizes, q->alloc_ctx);
- if (ret) {
- fail_qop(q, queue_setup);
+ if (ret)
return ret;
- }
/* Finally, allocate buffers and video memory */
allocated_buffers = __vb2_queue_alloc(q, req->memory, num_buffers, num_planes);
if (allocated_buffers == 0) {
- dprintk(1, "Memory allocation failed\n");
+ dprintk(1, "memory allocation failed\n");
return -ENOMEM;
}
@@ -864,8 +941,6 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
ret = call_qop(q, queue_setup, q, NULL, &num_buffers,
&num_planes, q->plane_sizes, q->alloc_ctx);
- if (ret)
- fail_qop(q, queue_setup);
if (!ret && allocated_buffers < num_buffers)
ret = -ENOMEM;
@@ -931,8 +1006,7 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
int ret;
if (q->num_buffers == VIDEO_MAX_FRAME) {
- dprintk(1, "%s(): maximum number of buffers already allocated\n",
- __func__);
+ dprintk(1, "maximum number of buffers already allocated\n");
return -ENOBUFS;
}
@@ -950,16 +1024,14 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
*/
ret = call_qop(q, queue_setup, q, &create->format, &num_buffers,
&num_planes, q->plane_sizes, q->alloc_ctx);
- if (ret) {
- fail_qop(q, queue_setup);
+ if (ret)
return ret;
- }
/* Finally, allocate buffers and video memory */
allocated_buffers = __vb2_queue_alloc(q, create->memory, num_buffers,
num_planes);
if (allocated_buffers == 0) {
- dprintk(1, "Memory allocation failed\n");
+ dprintk(1, "memory allocation failed\n");
return -ENOMEM;
}
@@ -975,8 +1047,6 @@ static int __create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create
*/
ret = call_qop(q, queue_setup, q, &create->format, &num_buffers,
&num_planes, q->plane_sizes, q->alloc_ctx);
- if (ret)
- fail_qop(q, queue_setup);
if (!ret && allocated_buffers < num_buffers)
ret = -ENOMEM;
@@ -1038,7 +1108,7 @@ void *vb2_plane_vaddr(struct vb2_buffer *vb, unsigned int plane_no)
if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv)
return NULL;
- return call_memop(vb, vaddr, vb->planes[plane_no].mem_priv);
+ return call_ptr_memop(vb, vaddr, vb->planes[plane_no].mem_priv);
}
EXPORT_SYMBOL_GPL(vb2_plane_vaddr);
@@ -1059,7 +1129,7 @@ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no)
if (plane_no > vb->num_planes || !vb->planes[plane_no].mem_priv)
return NULL;
- return call_memop(vb, cookie, vb->planes[plane_no].mem_priv);
+ return call_ptr_memop(vb, cookie, vb->planes[plane_no].mem_priv);
}
EXPORT_SYMBOL_GPL(vb2_plane_cookie);
@@ -1094,9 +1164,8 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
if (!q->start_streaming_called) {
if (WARN_ON(state != VB2_BUF_STATE_QUEUED))
state = VB2_BUF_STATE_QUEUED;
- } else if (!WARN_ON(!q->start_streaming_called)) {
- if (WARN_ON(state != VB2_BUF_STATE_DONE &&
- state != VB2_BUF_STATE_ERROR))
+ } else if (WARN_ON(state != VB2_BUF_STATE_DONE &&
+ state != VB2_BUF_STATE_ERROR)) {
state = VB2_BUF_STATE_ERROR;
}
@@ -1107,12 +1176,12 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state)
*/
vb->cnt_buf_done++;
#endif
- dprintk(4, "Done processing on buffer %d, state: %d\n",
+ dprintk(4, "done processing on buffer %d, state: %d\n",
vb->v4l2_buf.index, state);
/* sync buffers */
for (plane = 0; plane < vb->num_planes; ++plane)
- call_memop(vb, finish, vb->planes[plane].mem_priv);
+ call_void_memop(vb, finish, vb->planes[plane].mem_priv);
/* Add the buffer to the done buffers list */
spin_lock_irqsave(&q->done_lock, flags);
@@ -1143,15 +1212,30 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b
if (V4L2_TYPE_IS_MULTIPLANAR(b->type)) {
/* Fill in driver-provided information for OUTPUT types */
if (V4L2_TYPE_IS_OUTPUT(b->type)) {
+ bool bytesused_is_used;
+
+ /* Check if bytesused == 0 for all planes */
+ for (plane = 0; plane < vb->num_planes; ++plane)
+ if (b->m.planes[plane].bytesused)
+ break;
+ bytesused_is_used = plane < vb->num_planes;
+
/*
* Will have to go up to b->length when API starts
* accepting variable number of planes.
+ *
+ * If bytesused_is_used is false, then fall back to the
+ * full buffer size. In that case userspace clearly
+ * never bothered to set it and it's a safe assumption
+ * that they really meant to use the full plane sizes.
*/
for (plane = 0; plane < vb->num_planes; ++plane) {
- v4l2_planes[plane].bytesused =
- b->m.planes[plane].bytesused;
- v4l2_planes[plane].data_offset =
- b->m.planes[plane].data_offset;
+ struct v4l2_plane *pdst = &v4l2_planes[plane];
+ struct v4l2_plane *psrc = &b->m.planes[plane];
+
+ pdst->bytesused = bytesused_is_used ?
+ psrc->bytesused : psrc->length;
+ pdst->data_offset = psrc->data_offset;
}
}
@@ -1169,8 +1253,6 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b
b->m.planes[plane].m.fd;
v4l2_planes[plane].length =
b->m.planes[plane].length;
- v4l2_planes[plane].data_offset =
- b->m.planes[plane].data_offset;
}
}
} else {
@@ -1179,11 +1261,15 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b
* so fill in relevant v4l2_buffer struct fields instead.
* In videobuf we use our internal V4l2_planes struct for
* single-planar buffers as well, for simplicity.
+ *
+ * If bytesused == 0, then fall back to the full buffer size
+ * as that's a sensible default.
*/
- if (V4L2_TYPE_IS_OUTPUT(b->type)) {
- v4l2_planes[0].bytesused = b->bytesused;
- v4l2_planes[0].data_offset = 0;
- }
+ if (V4L2_TYPE_IS_OUTPUT(b->type))
+ v4l2_planes[0].bytesused =
+ b->bytesused ? b->bytesused : b->length;
+ else
+ v4l2_planes[0].bytesused = 0;
if (b->memory == V4L2_MEMORY_USERPTR) {
v4l2_planes[0].m.userptr = b->m.userptr;
@@ -1193,9 +1279,7 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b
if (b->memory == V4L2_MEMORY_DMABUF) {
v4l2_planes[0].m.fd = b->m.fd;
v4l2_planes[0].length = b->length;
- v4l2_planes[0].data_offset = 0;
}
-
}
/* Zero flags that the vb2 core handles */
@@ -1226,6 +1310,15 @@ static void __fill_vb2_buffer(struct vb2_buffer *vb, const struct v4l2_buffer *b
}
/**
+ * __qbuf_mmap() - handle qbuf of an MMAP buffer
+ */
+static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b)
+{
+ __fill_vb2_buffer(vb, b, vb->v4l2_planes);
+ return call_vb_qop(vb, buf_prepare, vb);
+}
+
+/**
* __qbuf_userptr() - handle qbuf of a USERPTR buffer
*/
static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
@@ -1238,6 +1331,7 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
int write = !V4L2_TYPE_IS_OUTPUT(q->type);
bool reacquired = vb->planes[0].mem_priv == NULL;
+ memset(planes, 0, sizeof(planes[0]) * vb->num_planes);
/* Copy relevant information provided by the userspace */
__fill_vb2_buffer(vb, b, planes);
@@ -1248,12 +1342,12 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
&& vb->v4l2_planes[plane].length == planes[plane].length)
continue;
- dprintk(3, "qbuf: userspace address for plane %d changed, "
+ dprintk(3, "userspace address for plane %d changed, "
"reacquiring memory\n", plane);
/* Check if the provided plane buffer is large enough */
if (planes[plane].length < q->plane_sizes[plane]) {
- dprintk(1, "qbuf: provided buffer size %u is less than "
+ dprintk(1, "provided buffer size %u is less than "
"setup size %u for plane %d\n",
planes[plane].length,
q->plane_sizes[plane], plane);
@@ -1265,22 +1359,21 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
if (vb->planes[plane].mem_priv) {
if (!reacquired) {
reacquired = true;
- call_vb_qop(vb, buf_cleanup, vb);
+ call_void_vb_qop(vb, buf_cleanup, vb);
}
- call_memop(vb, put_userptr, vb->planes[plane].mem_priv);
+ call_void_memop(vb, put_userptr, vb->planes[plane].mem_priv);
}
vb->planes[plane].mem_priv = NULL;
memset(&vb->v4l2_planes[plane], 0, sizeof(struct v4l2_plane));
/* Acquire each plane's memory */
- mem_priv = call_memop(vb, get_userptr, q->alloc_ctx[plane],
+ mem_priv = call_ptr_memop(vb, get_userptr, q->alloc_ctx[plane],
planes[plane].m.userptr,
planes[plane].length, write);
if (IS_ERR_OR_NULL(mem_priv)) {
- dprintk(1, "qbuf: failed acquiring userspace "
+ dprintk(1, "failed acquiring userspace "
"memory for plane %d\n", plane);
- fail_memop(vb, get_userptr);
ret = mem_priv ? PTR_ERR(mem_priv) : -EINVAL;
goto err;
}
@@ -1302,17 +1395,15 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
*/
ret = call_vb_qop(vb, buf_init, vb);
if (ret) {
- dprintk(1, "qbuf: buffer initialization failed\n");
- fail_vb_qop(vb, buf_init);
+ dprintk(1, "buffer initialization failed\n");
goto err;
}
}
ret = call_vb_qop(vb, buf_prepare, vb);
if (ret) {
- dprintk(1, "qbuf: buffer preparation failed\n");
- fail_vb_qop(vb, buf_prepare);
- call_vb_qop(vb, buf_cleanup, vb);
+ dprintk(1, "buffer preparation failed\n");
+ call_void_vb_qop(vb, buf_cleanup, vb);
goto err;
}
@@ -1321,7 +1412,7 @@ err:
/* In case of errors, release planes that were already acquired */
for (plane = 0; plane < vb->num_planes; ++plane) {
if (vb->planes[plane].mem_priv)
- call_memop(vb, put_userptr, vb->planes[plane].mem_priv);
+ call_void_memop(vb, put_userptr, vb->planes[plane].mem_priv);
vb->planes[plane].mem_priv = NULL;
vb->v4l2_planes[plane].m.userptr = 0;
vb->v4l2_planes[plane].length = 0;
@@ -1331,20 +1422,6 @@ err:
}
/**
- * __qbuf_mmap() - handle qbuf of an MMAP buffer
- */
-static int __qbuf_mmap(struct vb2_buffer *vb, const struct v4l2_buffer *b)
-{
- int ret;
-
- __fill_vb2_buffer(vb, b, vb->v4l2_planes);
- ret = call_vb_qop(vb, buf_prepare, vb);
- if (ret)
- fail_vb_qop(vb, buf_prepare);
- return ret;
-}
-
-/**
* __qbuf_dmabuf() - handle qbuf of a DMABUF buffer
*/
static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
@@ -1357,6 +1434,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
int write = !V4L2_TYPE_IS_OUTPUT(q->type);
bool reacquired = vb->planes[0].mem_priv == NULL;
+ memset(planes, 0, sizeof(planes[0]) * vb->num_planes);
/* Copy relevant information provided by the userspace */
__fill_vb2_buffer(vb, b, planes);
@@ -1364,7 +1442,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
struct dma_buf *dbuf = dma_buf_get(planes[plane].m.fd);
if (IS_ERR_OR_NULL(dbuf)) {
- dprintk(1, "qbuf: invalid dmabuf fd for plane %d\n",
+ dprintk(1, "invalid dmabuf fd for plane %d\n",
plane);
ret = -EINVAL;
goto err;
@@ -1374,9 +1452,8 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
if (planes[plane].length == 0)
planes[plane].length = dbuf->size;
- if (planes[plane].length < planes[plane].data_offset +
- q->plane_sizes[plane]) {
- dprintk(1, "qbuf: invalid dmabuf length for plane %d\n",
+ if (planes[plane].length < q->plane_sizes[plane]) {
+ dprintk(1, "invalid dmabuf length for plane %d\n",
plane);
ret = -EINVAL;
goto err;
@@ -1389,11 +1466,11 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
continue;
}
- dprintk(1, "qbuf: buffer for plane %d changed\n", plane);
+ dprintk(1, "buffer for plane %d changed\n", plane);
if (!reacquired) {
reacquired = true;
- call_vb_qop(vb, buf_cleanup, vb);
+ call_void_vb_qop(vb, buf_cleanup, vb);
}
/* Release previously acquired memory if present */
@@ -1401,11 +1478,10 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
memset(&vb->v4l2_planes[plane], 0, sizeof(struct v4l2_plane));
/* Acquire each plane's memory */
- mem_priv = call_memop(vb, attach_dmabuf, q->alloc_ctx[plane],
+ mem_priv = call_ptr_memop(vb, attach_dmabuf, q->alloc_ctx[plane],
dbuf, planes[plane].length, write);
if (IS_ERR(mem_priv)) {
- dprintk(1, "qbuf: failed to attach dmabuf\n");
- fail_memop(vb, attach_dmabuf);
+ dprintk(1, "failed to attach dmabuf\n");
ret = PTR_ERR(mem_priv);
dma_buf_put(dbuf);
goto err;
@@ -1422,9 +1498,8 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
for (plane = 0; plane < vb->num_planes; ++plane) {
ret = call_memop(vb, map_dmabuf, vb->planes[plane].mem_priv);
if (ret) {
- dprintk(1, "qbuf: failed to map dmabuf for plane %d\n",
+ dprintk(1, "failed to map dmabuf for plane %d\n",
plane);
- fail_memop(vb, map_dmabuf);
goto err;
}
vb->planes[plane].dbuf_mapped = 1;
@@ -1444,17 +1519,15 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
*/
ret = call_vb_qop(vb, buf_init, vb);
if (ret) {
- dprintk(1, "qbuf: buffer initialization failed\n");
- fail_vb_qop(vb, buf_init);
+ dprintk(1, "buffer initialization failed\n");
goto err;
}
}
ret = call_vb_qop(vb, buf_prepare, vb);
if (ret) {
- dprintk(1, "qbuf: buffer preparation failed\n");
- fail_vb_qop(vb, buf_prepare);
- call_vb_qop(vb, buf_cleanup, vb);
+ dprintk(1, "buffer preparation failed\n");
+ call_void_vb_qop(vb, buf_cleanup, vb);
goto err;
}
@@ -1479,9 +1552,9 @@ static void __enqueue_in_driver(struct vb2_buffer *vb)
/* sync buffers */
for (plane = 0; plane < vb->num_planes; ++plane)
- call_memop(vb, prepare, vb->planes[plane].mem_priv);
+ call_void_memop(vb, prepare, vb->planes[plane].mem_priv);
- call_vb_qop(vb, buf_queue, vb);
+ call_void_vb_qop(vb, buf_queue, vb);
}
static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
@@ -1492,10 +1565,22 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
ret = __verify_length(vb, b);
if (ret < 0) {
- dprintk(1, "%s(): plane parameters verification failed: %d\n",
- __func__, ret);
+ dprintk(1, "plane parameters verification failed: %d\n", ret);
return ret;
}
+ if (b->field == V4L2_FIELD_ALTERNATE && V4L2_TYPE_IS_OUTPUT(q->type)) {
+ /*
+ * If the format's field is ALTERNATE, then the buffer's field
+ * should be either TOP or BOTTOM, not ALTERNATE since that
+ * makes no sense. The driver has to know whether the
+ * buffer represents a top or a bottom field in order to
+ * program any DMA correctly. Using ALTERNATE is wrong, since
+ * that just says that it is either a top or a bottom field,
+ * but not which of the two it is.
+ */
+ dprintk(1, "the field is incorrectly set to ALTERNATE for an output buffer\n");
+ return -EINVAL;
+ }
vb->state = VB2_BUF_STATE_PREPARING;
vb->v4l2_buf.timestamp.tv_sec = 0;
@@ -1520,9 +1605,9 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
* mmap_sem and then takes the driver's lock again.
*/
mmap_sem = &current->mm->mmap_sem;
- call_qop(q, wait_prepare, q);
+ call_void_qop(q, wait_prepare, q);
down_read(mmap_sem);
- call_qop(q, wait_finish, q);
+ call_void_qop(q, wait_finish, q);
ret = __qbuf_userptr(vb, b);
@@ -1537,7 +1622,7 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
}
if (ret)
- dprintk(1, "qbuf: buffer preparation failed: %d\n", ret);
+ dprintk(1, "buffer preparation failed: %d\n", ret);
vb->state = ret ? VB2_BUF_STATE_DEQUEUED : VB2_BUF_STATE_PREPARED;
return ret;
@@ -1547,23 +1632,23 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
const char *opname)
{
if (b->type != q->type) {
- dprintk(1, "%s(): invalid buffer type\n", opname);
+ dprintk(1, "%s: invalid buffer type\n", opname);
return -EINVAL;
}
if (b->index >= q->num_buffers) {
- dprintk(1, "%s(): buffer index out of range\n", opname);
+ dprintk(1, "%s: buffer index out of range\n", opname);
return -EINVAL;
}
if (q->bufs[b->index] == NULL) {
/* Should never happen */
- dprintk(1, "%s(): buffer is NULL\n", opname);
+ dprintk(1, "%s: buffer is NULL\n", opname);
return -EINVAL;
}
if (b->memory != q->memory) {
- dprintk(1, "%s(): invalid memory type\n", opname);
+ dprintk(1, "%s: invalid memory type\n", opname);
return -EINVAL;
}
@@ -1590,8 +1675,8 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b)
struct vb2_buffer *vb;
int ret;
- if (q->fileio) {
- dprintk(1, "%s(): file io in progress\n", __func__);
+ if (vb2_fileio_is_active(q)) {
+ dprintk(1, "file io in progress\n");
return -EBUSY;
}
@@ -1601,7 +1686,7 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b)
vb = q->bufs[b->index];
if (vb->state != VB2_BUF_STATE_DEQUEUED) {
- dprintk(1, "%s(): invalid buffer state %d\n", __func__,
+ dprintk(1, "invalid buffer state %d\n",
vb->state);
return -EINVAL;
}
@@ -1611,7 +1696,7 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b)
/* Fill buffer information for the userspace */
__fill_v4l2_buffer(vb, b);
- dprintk(1, "%s() of buffer %d succeeded\n", __func__, vb->v4l2_buf.index);
+ dprintk(1, "prepare of buffer %d succeeded\n", vb->v4l2_buf.index);
}
return ret;
}
@@ -1647,8 +1732,7 @@ static int vb2_start_streaming(struct vb2_queue *q)
if (!ret)
return 0;
- fail_qop(q, start_streaming);
- dprintk(1, "qbuf: driver refused to start streaming\n");
+ dprintk(1, "driver refused to start streaming\n");
if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
unsigned i;
@@ -1686,11 +1770,10 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
case VB2_BUF_STATE_PREPARED:
break;
case VB2_BUF_STATE_PREPARING:
- dprintk(1, "qbuf: buffer still being prepared\n");
+ dprintk(1, "buffer still being prepared\n");
return -EINVAL;
default:
- dprintk(1, "%s(): invalid buffer state %d\n", __func__,
- vb->state);
+ dprintk(1, "invalid buffer state %d\n", vb->state);
return -EINVAL;
}
@@ -1737,7 +1820,7 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
return ret;
}
- dprintk(1, "%s() of buffer %d succeeded\n", __func__, vb->v4l2_buf.index);
+ dprintk(1, "qbuf of buffer %d succeeded\n", vb->v4l2_buf.index);
return 0;
}
@@ -1760,8 +1843,8 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
*/
int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
{
- if (q->fileio) {
- dprintk(1, "%s(): file io in progress\n", __func__);
+ if (vb2_fileio_is_active(q)) {
+ dprintk(1, "file io in progress\n");
return -EBUSY;
}
@@ -1790,7 +1873,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
int ret;
if (!q->streaming) {
- dprintk(1, "Streaming off, will not wait for buffers\n");
+ dprintk(1, "streaming off, will not wait for buffers\n");
return -EINVAL;
}
@@ -1802,7 +1885,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
}
if (nonblocking) {
- dprintk(1, "Nonblocking and no buffers to dequeue, "
+ dprintk(1, "nonblocking and no buffers to dequeue, "
"will not wait\n");
return -EAGAIN;
}
@@ -1812,12 +1895,12 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
* become ready or for streamoff. Driver's lock is released to
* allow streamoff or qbuf to be called while waiting.
*/
- call_qop(q, wait_prepare, q);
+ call_void_qop(q, wait_prepare, q);
/*
* All locks have been released, it is safe to sleep now.
*/
- dprintk(3, "Will sleep waiting for buffers\n");
+ dprintk(3, "will sleep waiting for buffers\n");
ret = wait_event_interruptible(q->done_wq,
!list_empty(&q->done_list) || !q->streaming);
@@ -1825,9 +1908,9 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
* We need to reevaluate both conditions again after reacquiring
* the locks or return an error if one occurred.
*/
- call_qop(q, wait_finish, q);
+ call_void_qop(q, wait_finish, q);
if (ret) {
- dprintk(1, "Sleep was interrupted\n");
+ dprintk(1, "sleep was interrupted\n");
return ret;
}
}
@@ -1882,7 +1965,7 @@ static int __vb2_get_done_vb(struct vb2_queue *q, struct vb2_buffer **vb,
int vb2_wait_for_all_buffers(struct vb2_queue *q)
{
if (!q->streaming) {
- dprintk(1, "Streaming off, will not wait for buffers\n");
+ dprintk(1, "streaming off, will not wait for buffers\n");
return -EINVAL;
}
@@ -1911,7 +1994,7 @@ static void __vb2_dqbuf(struct vb2_buffer *vb)
for (i = 0; i < vb->num_planes; ++i) {
if (!vb->planes[i].dbuf_mapped)
continue;
- call_memop(vb, unmap_dmabuf, vb->planes[i].mem_priv);
+ call_void_memop(vb, unmap_dmabuf, vb->planes[i].mem_priv);
vb->planes[i].dbuf_mapped = 0;
}
}
@@ -1922,7 +2005,7 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n
int ret;
if (b->type != q->type) {
- dprintk(1, "dqbuf: invalid buffer type\n");
+ dprintk(1, "invalid buffer type\n");
return -EINVAL;
}
ret = __vb2_get_done_vb(q, &vb, b, nonblocking);
@@ -1931,17 +2014,17 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n
switch (vb->state) {
case VB2_BUF_STATE_DONE:
- dprintk(3, "dqbuf: Returning done buffer\n");
+ dprintk(3, "returning done buffer\n");
break;
case VB2_BUF_STATE_ERROR:
- dprintk(3, "dqbuf: Returning done buffer with errors\n");
+ dprintk(3, "returning done buffer with errors\n");
break;
default:
- dprintk(1, "dqbuf: Invalid buffer state\n");
+ dprintk(1, "invalid buffer state\n");
return -EINVAL;
}
- call_vb_qop(vb, buf_finish, vb);
+ call_void_vb_qop(vb, buf_finish, vb);
/* Fill buffer information for the userspace */
__fill_v4l2_buffer(vb, b);
@@ -1980,8 +2063,8 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n
*/
int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
{
- if (q->fileio) {
- dprintk(1, "dqbuf: file io in progress\n");
+ if (vb2_fileio_is_active(q)) {
+ dprintk(1, "file io in progress\n");
return -EBUSY;
}
return vb2_internal_dqbuf(q, b, nonblocking);
@@ -2003,10 +2086,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
* buffers.
*/
if (q->start_streaming_called)
- call_qop(q, stop_streaming, q);
- q->streaming = 0;
- q->start_streaming_called = 0;
- q->queued_count = 0;
+ call_void_qop(q, stop_streaming, q);
if (WARN_ON(atomic_read(&q->owned_by_drv_count))) {
for (i = 0; i < q->num_buffers; ++i)
@@ -2016,6 +2096,10 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
WARN_ON(atomic_read(&q->owned_by_drv_count));
}
+ q->streaming = 0;
+ q->start_streaming_called = 0;
+ q->queued_count = 0;
+
/*
* Remove all buffers from videobuf's list...
*/
@@ -2042,7 +2126,7 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
if (vb->state != VB2_BUF_STATE_DEQUEUED) {
vb->state = VB2_BUF_STATE_PREPARED;
- call_vb_qop(vb, buf_finish, vb);
+ call_void_vb_qop(vb, buf_finish, vb);
}
__vb2_dqbuf(vb);
}
@@ -2053,26 +2137,22 @@ static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
int ret;
if (type != q->type) {
- dprintk(1, "streamon: invalid stream type\n");
+ dprintk(1, "invalid stream type\n");
return -EINVAL;
}
if (q->streaming) {
- dprintk(3, "streamon successful: already streaming\n");
+ dprintk(3, "already streaming\n");
return 0;
}
if (!q->num_buffers) {
- dprintk(1, "streamon: no buffers have been allocated\n");
+ dprintk(1, "no buffers have been allocated\n");
return -EINVAL;
}
- if (!q->num_buffers) {
- dprintk(1, "streamon: no buffers have been allocated\n");
- return -EINVAL;
- }
if (q->num_buffers < q->min_buffers_needed) {
- dprintk(1, "streamon: need at least %u allocated buffers\n",
+ dprintk(1, "need at least %u allocated buffers\n",
q->min_buffers_needed);
return -EINVAL;
}
@@ -2091,7 +2171,7 @@ static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
q->streaming = 1;
- dprintk(3, "Streamon successful\n");
+ dprintk(3, "successful\n");
return 0;
}
@@ -2110,8 +2190,8 @@ static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
*/
int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
{
- if (q->fileio) {
- dprintk(1, "streamon: file io in progress\n");
+ if (vb2_fileio_is_active(q)) {
+ dprintk(1, "file io in progress\n");
return -EBUSY;
}
return vb2_internal_streamon(q, type);
@@ -2121,7 +2201,7 @@ EXPORT_SYMBOL_GPL(vb2_streamon);
static int vb2_internal_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
{
if (type != q->type) {
- dprintk(1, "streamoff: invalid stream type\n");
+ dprintk(1, "invalid stream type\n");
return -EINVAL;
}
@@ -2136,7 +2216,7 @@ static int vb2_internal_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
*/
__vb2_queue_cancel(q);
- dprintk(3, "Streamoff successful\n");
+ dprintk(3, "successful\n");
return 0;
}
@@ -2157,8 +2237,8 @@ static int vb2_internal_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
*/
int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
{
- if (q->fileio) {
- dprintk(1, "streamoff: file io in progress\n");
+ if (vb2_fileio_is_active(q)) {
+ dprintk(1, "file io in progress\n");
return -EBUSY;
}
return vb2_internal_streamoff(q, type);
@@ -2211,22 +2291,22 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb)
struct dma_buf *dbuf;
if (q->memory != V4L2_MEMORY_MMAP) {
- dprintk(1, "Queue is not currently set up for mmap\n");
+ dprintk(1, "queue is not currently set up for mmap\n");
return -EINVAL;
}
if (!q->mem_ops->get_dmabuf) {
- dprintk(1, "Queue does not support DMA buffer exporting\n");
+ dprintk(1, "queue does not support DMA buffer exporting\n");
return -EINVAL;
}
if (eb->flags & ~(O_CLOEXEC | O_ACCMODE)) {
- dprintk(1, "Queue does support only O_CLOEXEC and access mode flags\n");
+ dprintk(1, "queue does support only O_CLOEXEC and access mode flags\n");
return -EINVAL;
}
if (eb->type != q->type) {
- dprintk(1, "qbuf: invalid buffer type\n");
+ dprintk(1, "invalid buffer type\n");
return -EINVAL;
}
@@ -2242,13 +2322,17 @@ int vb2_expbuf(struct vb2_queue *q, struct v4l2_exportbuffer *eb)
return -EINVAL;
}
+ if (vb2_fileio_is_active(q)) {
+ dprintk(1, "expbuf: file io in progress\n");
+ return -EBUSY;
+ }
+
vb_plane = &vb->planes[eb->plane];
- dbuf = call_memop(vb, get_dmabuf, vb_plane->mem_priv, eb->flags & O_ACCMODE);
+ dbuf = call_ptr_memop(vb, get_dmabuf, vb_plane->mem_priv, eb->flags & O_ACCMODE);
if (IS_ERR_OR_NULL(dbuf)) {
- dprintk(1, "Failed to export buffer %d, plane %d\n",
+ dprintk(1, "failed to export buffer %d, plane %d\n",
eb->index, eb->plane);
- fail_memop(vb, get_dmabuf);
return -EINVAL;
}
@@ -2291,12 +2375,12 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
{
unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
struct vb2_buffer *vb;
- unsigned int buffer, plane;
+ unsigned int buffer = 0, plane = 0;
int ret;
unsigned long length;
if (q->memory != V4L2_MEMORY_MMAP) {
- dprintk(1, "Queue is not currently set up for mmap\n");
+ dprintk(1, "queue is not currently set up for mmap\n");
return -EINVAL;
}
@@ -2304,20 +2388,24 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
* Check memory area access mode.
*/
if (!(vma->vm_flags & VM_SHARED)) {
- dprintk(1, "Invalid vma flags, VM_SHARED needed\n");
+ dprintk(1, "invalid vma flags, VM_SHARED needed\n");
return -EINVAL;
}
if (V4L2_TYPE_IS_OUTPUT(q->type)) {
if (!(vma->vm_flags & VM_WRITE)) {
- dprintk(1, "Invalid vma flags, VM_WRITE needed\n");
+ dprintk(1, "invalid vma flags, VM_WRITE needed\n");
return -EINVAL;
}
} else {
if (!(vma->vm_flags & VM_READ)) {
- dprintk(1, "Invalid vma flags, VM_READ needed\n");
+ dprintk(1, "invalid vma flags, VM_READ needed\n");
return -EINVAL;
}
}
+ if (vb2_fileio_is_active(q)) {
+ dprintk(1, "mmap: file io in progress\n");
+ return -EBUSY;
+ }
/*
* Find the plane corresponding to the offset passed by userspace.
@@ -2341,12 +2429,10 @@ int vb2_mmap(struct vb2_queue *q, struct vm_area_struct *vma)
}
ret = call_memop(vb, mmap, vb->planes[plane].mem_priv, vma);
- if (ret) {
- fail_memop(vb, mmap);
+ if (ret)
return ret;
- }
- dprintk(3, "Buffer %d, plane %d successfully mapped\n", buffer, plane);
+ dprintk(3, "buffer %d, plane %d successfully mapped\n", buffer, plane);
return 0;
}
EXPORT_SYMBOL_GPL(vb2_mmap);
@@ -2364,7 +2450,7 @@ unsigned long vb2_get_unmapped_area(struct vb2_queue *q,
int ret;
if (q->memory != V4L2_MEMORY_MMAP) {
- dprintk(1, "Queue is not currently set up for mmap\n");
+ dprintk(1, "queue is not currently set up for mmap\n");
return -EINVAL;
}
@@ -2429,7 +2515,7 @@ unsigned int vb2_poll(struct vb2_queue *q, struct file *file, poll_table *wait)
/*
* Start file I/O emulator only if streaming API has not been used yet.
*/
- if (q->num_buffers == 0 && q->fileio == NULL) {
+ if (q->num_buffers == 0 && !vb2_fileio_is_active(q)) {
if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ) &&
(req_events & (POLLIN | POLLRDNORM))) {
if (__vb2_init_fileio(q, 1))
@@ -2574,6 +2660,7 @@ struct vb2_fileio_buf {
*/
struct vb2_fileio_data {
struct v4l2_requestbuffers req;
+ struct v4l2_plane p;
struct v4l2_buffer b;
struct vb2_fileio_buf bufs[VIDEO_MAX_FRAME];
unsigned int cur_index;
@@ -2634,7 +2721,8 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
fileio->req.count = count;
fileio->req.memory = V4L2_MEMORY_MMAP;
fileio->req.type = q->type;
- ret = vb2_reqbufs(q, &fileio->req);
+ q->fileio = fileio;
+ ret = __reqbufs(q, &fileio->req);
if (ret)
goto err_kfree;
@@ -2663,16 +2751,24 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
* Read mode requires pre queuing of all buffers.
*/
if (read) {
+ bool is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(q->type);
+
/*
* Queue all buffers.
*/
for (i = 0; i < q->num_buffers; i++) {
struct v4l2_buffer *b = &fileio->b;
+
memset(b, 0, sizeof(*b));
b->type = q->type;
+ if (is_multiplanar) {
+ memset(&fileio->p, 0, sizeof(fileio->p));
+ b->m.planes = &fileio->p;
+ b->length = 1;
+ }
b->memory = q->memory;
b->index = i;
- ret = vb2_qbuf(q, b);
+ ret = vb2_internal_qbuf(q, b);
if (ret)
goto err_reqbufs;
fileio->bufs[i].queued = 1;
@@ -2688,19 +2784,18 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
/*
* Start streaming.
*/
- ret = vb2_streamon(q, q->type);
+ ret = vb2_internal_streamon(q, q->type);
if (ret)
goto err_reqbufs;
- q->fileio = fileio;
-
return ret;
err_reqbufs:
fileio->req.count = 0;
- vb2_reqbufs(q, &fileio->req);
+ __reqbufs(q, &fileio->req);
err_kfree:
+ q->fileio = NULL;
kfree(fileio);
return ret;
}
@@ -2738,9 +2833,18 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
{
struct vb2_fileio_data *fileio;
struct vb2_fileio_buf *buf;
+ bool is_multiplanar = V4L2_TYPE_IS_MULTIPLANAR(q->type);
+ /*
+ * When using write() to write data to an output video node the vb2 core
+ * should set timestamps if V4L2_BUF_FLAG_TIMESTAMP_COPY is set. Nobody
+ * else is able to provide this information with the write() operation.
+ */
+ bool set_timestamp = !read &&
+ (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
+ V4L2_BUF_FLAG_TIMESTAMP_COPY;
int ret, index;
- dprintk(3, "file io: mode %s, offset %ld, count %zd, %sblocking\n",
+ dprintk(3, "mode %s, offset %ld, count %zd, %sblocking\n",
read ? "read" : "write", (long)*ppos, count,
nonblock ? "non" : "");
@@ -2750,9 +2854,9 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
/*
* Initialize emulator on first call.
*/
- if (!q->fileio) {
+ if (!vb2_fileio_is_active(q)) {
ret = __vb2_init_fileio(q, read);
- dprintk(3, "file io: vb2_init_fileio result: %d\n", ret);
+ dprintk(3, "vb2_init_fileio result: %d\n", ret);
if (ret)
return ret;
}
@@ -2769,8 +2873,13 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
memset(&fileio->b, 0, sizeof(fileio->b));
fileio->b.type = q->type;
fileio->b.memory = q->memory;
+ if (is_multiplanar) {
+ memset(&fileio->p, 0, sizeof(fileio->p));
+ fileio->b.m.planes = &fileio->p;
+ fileio->b.length = 1;
+ }
ret = vb2_internal_dqbuf(q, &fileio->b, nonblock);
- dprintk(5, "file io: vb2_dqbuf result: %d\n", ret);
+ dprintk(5, "vb2_dqbuf result: %d\n", ret);
if (ret)
return ret;
fileio->dq_count += 1;
@@ -2800,14 +2909,14 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
/*
* Transfer data to userspace.
*/
- dprintk(3, "file io: copying %zd bytes - buffer %d, offset %u\n",
+ dprintk(3, "copying %zd bytes - buffer %d, offset %u\n",
count, index, buf->pos);
if (read)
ret = copy_to_user(data, buf->vaddr + buf->pos, count);
else
ret = copy_from_user(buf->vaddr + buf->pos, data, count);
if (ret) {
- dprintk(3, "file io: error copying data\n");
+ dprintk(3, "error copying data\n");
return -EFAULT;
}
@@ -2827,7 +2936,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
*/
if (read && (fileio->flags & VB2_FILEIO_READ_ONCE) &&
fileio->dq_count == 1) {
- dprintk(3, "file io: read limit reached\n");
+ dprintk(3, "read limit reached\n");
return __vb2_cleanup_fileio(q);
}
@@ -2839,8 +2948,16 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
fileio->b.memory = q->memory;
fileio->b.index = index;
fileio->b.bytesused = buf->pos;
+ if (is_multiplanar) {
+ memset(&fileio->p, 0, sizeof(fileio->p));
+ fileio->p.bytesused = buf->pos;
+ fileio->b.m.planes = &fileio->p;
+ fileio->b.length = 1;
+ }
+ if (set_timestamp)
+ v4l2_get_timestamp(&fileio->b.timestamp);
ret = vb2_internal_qbuf(q, &fileio->b);
- dprintk(5, "file io: vb2_dbuf result: %d\n", ret);
+ dprintk(5, "vb2_dbuf result: %d\n", ret);
if (ret)
return ret;
@@ -2890,6 +3007,147 @@ size_t vb2_write(struct vb2_queue *q, const char __user *data, size_t count,
}
EXPORT_SYMBOL_GPL(vb2_write);
+struct vb2_threadio_data {
+ struct task_struct *thread;
+ vb2_thread_fnc fnc;
+ void *priv;
+ bool stop;
+};
+
+static int vb2_thread(void *data)
+{
+ struct vb2_queue *q = data;
+ struct vb2_threadio_data *threadio = q->threadio;
+ struct vb2_fileio_data *fileio = q->fileio;
+ bool set_timestamp = false;
+ int prequeue = 0;
+ int index = 0;
+ int ret = 0;
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ prequeue = q->num_buffers;
+ set_timestamp =
+ (q->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MASK) ==
+ V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ }
+
+ set_freezable();
+
+ for (;;) {
+ struct vb2_buffer *vb;
+
+ /*
+ * Call vb2_dqbuf to get buffer back.
+ */
+ memset(&fileio->b, 0, sizeof(fileio->b));
+ fileio->b.type = q->type;
+ fileio->b.memory = q->memory;
+ if (prequeue) {
+ fileio->b.index = index++;
+ prequeue--;
+ } else {
+ call_void_qop(q, wait_finish, q);
+ ret = vb2_internal_dqbuf(q, &fileio->b, 0);
+ call_void_qop(q, wait_prepare, q);
+ dprintk(5, "file io: vb2_dqbuf result: %d\n", ret);
+ }
+ if (threadio->stop)
+ break;
+ if (ret)
+ break;
+ try_to_freeze();
+
+ vb = q->bufs[fileio->b.index];
+ if (!(fileio->b.flags & V4L2_BUF_FLAG_ERROR))
+ ret = threadio->fnc(vb, threadio->priv);
+ if (ret)
+ break;
+ call_void_qop(q, wait_finish, q);
+ if (set_timestamp)
+ v4l2_get_timestamp(&fileio->b.timestamp);
+ ret = vb2_internal_qbuf(q, &fileio->b);
+ call_void_qop(q, wait_prepare, q);
+ if (ret)
+ break;
+ }
+
+ /* Hmm, linux becomes *very* unhappy without this ... */
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ }
+ return 0;
+}
+
+/*
+ * This function should not be used for anything else but the videobuf2-dvb
+ * support. If you think you have another good use-case for this, then please
+ * contact the linux-media mailinglist first.
+ */
+int vb2_thread_start(struct vb2_queue *q, vb2_thread_fnc fnc, void *priv,
+ const char *thread_name)
+{
+ struct vb2_threadio_data *threadio;
+ int ret = 0;
+
+ if (q->threadio)
+ return -EBUSY;
+ if (vb2_is_busy(q))
+ return -EBUSY;
+ if (WARN_ON(q->fileio))
+ return -EBUSY;
+
+ threadio = kzalloc(sizeof(*threadio), GFP_KERNEL);
+ if (threadio == NULL)
+ return -ENOMEM;
+ threadio->fnc = fnc;
+ threadio->priv = priv;
+
+ ret = __vb2_init_fileio(q, !V4L2_TYPE_IS_OUTPUT(q->type));
+ dprintk(3, "file io: vb2_init_fileio result: %d\n", ret);
+ if (ret)
+ goto nomem;
+ q->threadio = threadio;
+ threadio->thread = kthread_run(vb2_thread, q, "vb2-%s", thread_name);
+ if (IS_ERR(threadio->thread)) {
+ ret = PTR_ERR(threadio->thread);
+ threadio->thread = NULL;
+ goto nothread;
+ }
+ return 0;
+
+nothread:
+ __vb2_cleanup_fileio(q);
+nomem:
+ kfree(threadio);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vb2_thread_start);
+
+int vb2_thread_stop(struct vb2_queue *q)
+{
+ struct vb2_threadio_data *threadio = q->threadio;
+ struct vb2_fileio_data *fileio = q->fileio;
+ int err;
+
+ if (threadio == NULL)
+ return 0;
+ call_void_qop(q, wait_finish, q);
+ threadio->stop = true;
+ vb2_internal_streamoff(q, q->type);
+ call_void_qop(q, wait_prepare, q);
+ q->fileio = NULL;
+ fileio->req.count = 0;
+ vb2_reqbufs(q, &fileio->req);
+ kfree(fileio);
+ err = kthread_stop(threadio->thread);
+ threadio->thread = NULL;
+ kfree(threadio);
+ q->fileio = NULL;
+ q->threadio = NULL;
+ return err;
+}
+EXPORT_SYMBOL_GPL(vb2_thread_stop);
/*
* The following functions are not part of the vb2 core API, but are helper
@@ -3116,7 +3374,7 @@ unsigned int vb2_fop_poll(struct file *file, poll_table *wait)
/* Try to be smart: only lock if polling might start fileio,
otherwise locking will only introduce unwanted delays. */
- if (q->num_buffers == 0 && q->fileio == NULL) {
+ if (q->num_buffers == 0 && !vb2_fileio_is_active(q)) {
if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ) &&
(req_events & (POLLIN | POLLRDNORM)))
must_lock = true;
diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index c779f210d2c6..adefc31bb853 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -211,7 +211,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
++num_pages_from_user, vaddr += PAGE_SIZE) {
unsigned long pfn;
- if (follow_pfn(buf->vma, vaddr, &pfn)) {
+ if (follow_pfn(vma, vaddr, &pfn)) {
dprintk(1, "no page for address %lu\n", vaddr);
break;
}
diff --git a/drivers/media/v4l2-core/videobuf2-dvb.c b/drivers/media/v4l2-core/videobuf2-dvb.c
new file mode 100644
index 000000000000..d09269846b7e
--- /dev/null
+++ b/drivers/media/v4l2-core/videobuf2-dvb.c
@@ -0,0 +1,336 @@
+/*
+ *
+ * some helper function for simple DVB cards which simply DMA the
+ * complete transport stream and let the computer sort everything else
+ * (i.e. we are using the software demux, ...). Also uses the
+ * video-buf to manage DMA buffers.
+ *
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]
+ *
+ * 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/init.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+
+#include <media/videobuf2-dvb.h>
+
+/* ------------------------------------------------------------------ */
+
+MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_LICENSE("GPL");
+
+/* ------------------------------------------------------------------ */
+
+static int dvb_fnc(struct vb2_buffer *vb, void *priv)
+{
+ struct vb2_dvb *dvb = priv;
+
+ dvb_dmx_swfilter(&dvb->demux, vb2_plane_vaddr(vb, 0),
+ vb2_get_plane_payload(vb, 0));
+ return 0;
+}
+
+static int vb2_dvb_start_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct vb2_dvb *dvb = demux->priv;
+ int rc = 0;
+
+ if (!demux->dmx.frontend)
+ return -EINVAL;
+
+ mutex_lock(&dvb->lock);
+ dvb->nfeeds++;
+
+ if (!dvb->dvbq.threadio) {
+ rc = vb2_thread_start(&dvb->dvbq, dvb_fnc, dvb, dvb->name);
+ if (rc)
+ dvb->nfeeds--;
+ }
+ if (!rc)
+ rc = dvb->nfeeds;
+ mutex_unlock(&dvb->lock);
+ return rc;
+}
+
+static int vb2_dvb_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct vb2_dvb *dvb = demux->priv;
+ int err = 0;
+
+ mutex_lock(&dvb->lock);
+ dvb->nfeeds--;
+ if (0 == dvb->nfeeds)
+ err = vb2_thread_stop(&dvb->dvbq);
+ mutex_unlock(&dvb->lock);
+ return err;
+}
+
+static int vb2_dvb_register_adapter(struct vb2_dvb_frontends *fe,
+ struct module *module,
+ void *adapter_priv,
+ struct device *device,
+ char *adapter_name,
+ short *adapter_nr,
+ int mfe_shared)
+{
+ int result;
+
+ mutex_init(&fe->lock);
+
+ /* register adapter */
+ result = dvb_register_adapter(&fe->adapter, adapter_name, module,
+ device, adapter_nr);
+ if (result < 0) {
+ pr_warn("%s: dvb_register_adapter failed (errno = %d)\n",
+ adapter_name, result);
+ }
+ fe->adapter.priv = adapter_priv;
+ fe->adapter.mfe_shared = mfe_shared;
+
+ return result;
+}
+
+static int vb2_dvb_register_frontend(struct dvb_adapter *adapter,
+ struct vb2_dvb *dvb)
+{
+ int result;
+
+ /* register frontend */
+ result = dvb_register_frontend(adapter, dvb->frontend);
+ if (result < 0) {
+ pr_warn("%s: dvb_register_frontend failed (errno = %d)\n",
+ dvb->name, result);
+ goto fail_frontend;
+ }
+
+ /* register demux stuff */
+ dvb->demux.dmx.capabilities =
+ DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+ dvb->demux.priv = dvb;
+ dvb->demux.filternum = 256;
+ dvb->demux.feednum = 256;
+ dvb->demux.start_feed = vb2_dvb_start_feed;
+ dvb->demux.stop_feed = vb2_dvb_stop_feed;
+ result = dvb_dmx_init(&dvb->demux);
+ if (result < 0) {
+ pr_warn("%s: dvb_dmx_init failed (errno = %d)\n",
+ dvb->name, result);
+ goto fail_dmx;
+ }
+
+ dvb->dmxdev.filternum = 256;
+ dvb->dmxdev.demux = &dvb->demux.dmx;
+ dvb->dmxdev.capabilities = 0;
+ result = dvb_dmxdev_init(&dvb->dmxdev, adapter);
+
+ if (result < 0) {
+ pr_warn("%s: dvb_dmxdev_init failed (errno = %d)\n",
+ dvb->name, result);
+ goto fail_dmxdev;
+ }
+
+ dvb->fe_hw.source = DMX_FRONTEND_0;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ pr_warn("%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
+ dvb->name, result);
+ goto fail_fe_hw;
+ }
+
+ dvb->fe_mem.source = DMX_MEMORY_FE;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+ if (result < 0) {
+ pr_warn("%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
+ dvb->name, result);
+ goto fail_fe_mem;
+ }
+
+ result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ pr_warn("%s: connect_frontend failed (errno = %d)\n",
+ dvb->name, result);
+ goto fail_fe_conn;
+ }
+
+ /* register network adapter */
+ result = dvb_net_init(adapter, &dvb->net, &dvb->demux.dmx);
+ if (result < 0) {
+ pr_warn("%s: dvb_net_init failed (errno = %d)\n",
+ dvb->name, result);
+ goto fail_fe_conn;
+ }
+ return 0;
+
+fail_fe_conn:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+ dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+ dvb_dmx_release(&dvb->demux);
+fail_dmx:
+ dvb_unregister_frontend(dvb->frontend);
+fail_frontend:
+ dvb_frontend_detach(dvb->frontend);
+ dvb->frontend = NULL;
+
+ return result;
+}
+
+/* ------------------------------------------------------------------ */
+/* Register a single adapter and one or more frontends */
+int vb2_dvb_register_bus(struct vb2_dvb_frontends *f,
+ struct module *module,
+ void *adapter_priv,
+ struct device *device,
+ short *adapter_nr,
+ int mfe_shared)
+{
+ struct list_head *list, *q;
+ struct vb2_dvb_frontend *fe;
+ int res;
+
+ fe = vb2_dvb_get_frontend(f, 1);
+ if (!fe) {
+ pr_warn("Unable to register the adapter which has no frontends\n");
+ return -EINVAL;
+ }
+
+ /* Bring up the adapter */
+ res = vb2_dvb_register_adapter(f, module, adapter_priv, device,
+ fe->dvb.name, adapter_nr, mfe_shared);
+ if (res < 0) {
+ pr_warn("vb2_dvb_register_adapter failed (errno = %d)\n", res);
+ return res;
+ }
+
+ /* Attach all of the frontends to the adapter */
+ mutex_lock(&f->lock);
+ list_for_each_safe(list, q, &f->felist) {
+ fe = list_entry(list, struct vb2_dvb_frontend, felist);
+ res = vb2_dvb_register_frontend(&f->adapter, &fe->dvb);
+ if (res < 0) {
+ pr_warn("%s: vb2_dvb_register_frontend failed (errno = %d)\n",
+ fe->dvb.name, res);
+ goto err;
+ }
+ }
+ mutex_unlock(&f->lock);
+ return 0;
+
+err:
+ mutex_unlock(&f->lock);
+ vb2_dvb_unregister_bus(f);
+ return res;
+}
+EXPORT_SYMBOL(vb2_dvb_register_bus);
+
+void vb2_dvb_unregister_bus(struct vb2_dvb_frontends *f)
+{
+ vb2_dvb_dealloc_frontends(f);
+
+ dvb_unregister_adapter(&f->adapter);
+}
+EXPORT_SYMBOL(vb2_dvb_unregister_bus);
+
+struct vb2_dvb_frontend *vb2_dvb_get_frontend(
+ struct vb2_dvb_frontends *f, int id)
+{
+ struct list_head *list, *q;
+ struct vb2_dvb_frontend *fe, *ret = NULL;
+
+ mutex_lock(&f->lock);
+
+ list_for_each_safe(list, q, &f->felist) {
+ fe = list_entry(list, struct vb2_dvb_frontend, felist);
+ if (fe->id == id) {
+ ret = fe;
+ break;
+ }
+ }
+
+ mutex_unlock(&f->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(vb2_dvb_get_frontend);
+
+int vb2_dvb_find_frontend(struct vb2_dvb_frontends *f,
+ struct dvb_frontend *p)
+{
+ struct list_head *list, *q;
+ struct vb2_dvb_frontend *fe = NULL;
+ int ret = 0;
+
+ mutex_lock(&f->lock);
+
+ list_for_each_safe(list, q, &f->felist) {
+ fe = list_entry(list, struct vb2_dvb_frontend, felist);
+ if (fe->dvb.frontend == p) {
+ ret = fe->id;
+ break;
+ }
+ }
+
+ mutex_unlock(&f->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(vb2_dvb_find_frontend);
+
+struct vb2_dvb_frontend *vb2_dvb_alloc_frontend(
+ struct vb2_dvb_frontends *f, int id)
+{
+ struct vb2_dvb_frontend *fe;
+
+ fe = kzalloc(sizeof(struct vb2_dvb_frontend), GFP_KERNEL);
+ if (fe == NULL)
+ return NULL;
+
+ fe->id = id;
+ mutex_init(&fe->dvb.lock);
+
+ mutex_lock(&f->lock);
+ list_add_tail(&fe->felist, &f->felist);
+ mutex_unlock(&f->lock);
+ return fe;
+}
+EXPORT_SYMBOL(vb2_dvb_alloc_frontend);
+
+void vb2_dvb_dealloc_frontends(struct vb2_dvb_frontends *f)
+{
+ struct list_head *list, *q;
+ struct vb2_dvb_frontend *fe;
+
+ mutex_lock(&f->lock);
+ list_for_each_safe(list, q, &f->felist) {
+ fe = list_entry(list, struct vb2_dvb_frontend, felist);
+ if (fe->dvb.net.dvbdev) {
+ dvb_net_release(&fe->dvb.net);
+ fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx,
+ &fe->dvb.fe_mem);
+ fe->dvb.demux.dmx.remove_frontend(&fe->dvb.demux.dmx,
+ &fe->dvb.fe_hw);
+ dvb_dmxdev_release(&fe->dvb.dmxdev);
+ dvb_dmx_release(&fe->dvb.demux);
+ dvb_unregister_frontend(fe->dvb.frontend);
+ }
+ if (fe->dvb.frontend)
+ /* always allocated, may have been reset */
+ dvb_frontend_detach(fe->dvb.frontend);
+ list_del(list); /* remove list entry */
+ kfree(fe); /* free frontend allocation */
+ }
+ mutex_unlock(&f->lock);
+}
+EXPORT_SYMBOL(vb2_dvb_dealloc_frontends);
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 7694e0700d34..b11fdd63eecd 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -1734,18 +1734,17 @@ static struct cpufreq_frequency_table db8500_cpufreq_table[] = {
static long round_armss_rate(unsigned long rate)
{
+ struct cpufreq_frequency_table *pos;
long freq = 0;
- int i = 0;
/* cpufreq table frequencies is in KHz. */
rate = rate / 1000;
/* Find the corresponding arm opp from the cpufreq table. */
- while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) {
- freq = db8500_cpufreq_table[i].frequency;
+ cpufreq_for_each_entry(pos, db8500_cpufreq_table) {
+ freq = pos->frequency;
if (freq == rate)
break;
- i++;
}
/* Return the last valid value, even if a match was not found. */
@@ -1886,23 +1885,21 @@ static void set_clock_rate(u8 clock, unsigned long rate)
static int set_armss_rate(unsigned long rate)
{
- int i = 0;
+ struct cpufreq_frequency_table *pos;
/* cpufreq table frequencies is in KHz. */
rate = rate / 1000;
/* Find the corresponding arm opp from the cpufreq table. */
- while (db8500_cpufreq_table[i].frequency != CPUFREQ_TABLE_END) {
- if (db8500_cpufreq_table[i].frequency == rate)
+ cpufreq_for_each_entry(pos, db8500_cpufreq_table)
+ if (pos->frequency == rate)
break;
- i++;
- }
- if (db8500_cpufreq_table[i].frequency != rate)
+ if (pos->frequency != rate)
return -EINVAL;
/* Set the new arm opp. */
- return db8500_prcmu_set_arm_opp(db8500_cpufreq_table[i].driver_data);
+ return db8500_prcmu_set_arm_opp(pos->driver_data);
}
static int set_plldsi_rate(unsigned long rate)
diff --git a/drivers/mfd/mc13xxx-core.c b/drivers/mfd/mc13xxx-core.c
index 06e64b6fcb89..0c6c21c5b1a8 100644
--- a/drivers/mfd/mc13xxx-core.c
+++ b/drivers/mfd/mc13xxx-core.c
@@ -673,9 +673,13 @@ int mc13xxx_common_init(struct device *dev)
if (mc13xxx->flags & MC13XXX_USE_ADC)
mc13xxx_add_subdevice(mc13xxx, "%s-adc");
- if (mc13xxx->flags & MC13XXX_USE_CODEC)
- mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
- pdata->codec, sizeof(*pdata->codec));
+ if (mc13xxx->flags & MC13XXX_USE_CODEC) {
+ if (pdata)
+ mc13xxx_add_subdevice_pdata(mc13xxx, "%s-codec",
+ pdata->codec, sizeof(*pdata->codec));
+ else
+ mc13xxx_add_subdevice(mc13xxx, "%s-codec");
+ }
if (mc13xxx->flags & MC13XXX_USE_RTC)
mc13xxx_add_subdevice(mc13xxx, "%s-rtc");
diff --git a/drivers/net/irda/sh_sir.c b/drivers/net/irda/sh_sir.c
index cadf52e22464..e3fe9a286136 100644
--- a/drivers/net/irda/sh_sir.c
+++ b/drivers/net/irda/sh_sir.c
@@ -217,21 +217,17 @@ crc_init_out:
static u32 sh_sir_find_sclk(struct clk *irda_clk)
{
struct cpufreq_frequency_table *freq_table = irda_clk->freq_table;
+ struct cpufreq_frequency_table *pos;
struct clk *pclk = clk_get(NULL, "peripheral_clk");
u32 limit, min = 0xffffffff, tmp;
- int i, index = 0;
+ int index = 0;
limit = clk_get_rate(pclk);
clk_put(pclk);
/* IrDA can not set over peripheral_clk */
- for (i = 0;
- freq_table[i].frequency != CPUFREQ_TABLE_END;
- i++) {
- u32 freq = freq_table[i].frequency;
-
- if (freq == CPUFREQ_ENTRY_INVALID)
- continue;
+ cpufreq_for_each_valid_entry(pos, freq_table) {
+ u32 freq = pos->frequency;
/* IrDA should not over peripheral_clk */
if (freq > limit)
@@ -240,7 +236,7 @@ static u32 sh_sir_find_sclk(struct clk *irda_clk)
tmp = freq % SCLK_BASE;
if (tmp < min) {
min = tmp;
- index = i;
+ index = pos - freq_table;
}
}
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 4fcc96aa9513..f51d5ca0141f 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -1265,7 +1265,7 @@ struct wmi_resource_config {
*/
__le32 rx_decap_mode;
- /* what is the maximum scan requests than can be queued */
+ /* what is the maximum number of scan requests that can be queued */
__le32 scan_max_pending_reqs;
/* maximum VDEV that could use BMISS offload */
@@ -1450,7 +1450,7 @@ struct wmi_resource_config_10x {
*/
__le32 rx_decap_mode;
- /* what is the maximum scan requests than can be queued */
+ /* what is the maximum number of scan requests that can be queued */
__le32 scan_max_pending_reqs;
/* maximum VDEV that could use BMISS offload */
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h
index b5f226503baf..5c702ae4d9f8 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.h
+++ b/drivers/net/wireless/ath/ath6kl/wmi.h
@@ -1068,7 +1068,7 @@ struct wmi_power_mode_cmd {
} __packed;
/*
- * Policy to determnine whether power save failure event should be sent to
+ * Policy to determine whether power save failure event should be sent to
* host during scanning
*/
enum power_save_fail_event_policy {
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 889005fa4d04..2dcb0541012d 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -20,6 +20,7 @@ config OF_SELFTEST
config OF_FLATTREE
bool
select DTC
+ select LIBFDT
config OF_EARLY_FLATTREE
bool
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index ed9660adad77..099b1fb00af4 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -1,5 +1,6 @@
obj-y = base.o device.o platform.o
obj-$(CONFIG_OF_FLATTREE) += fdt.o
+obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o
obj-$(CONFIG_OF_PROMTREE) += pdt.o
obj-$(CONFIG_OF_ADDRESS) += address.o
obj-$(CONFIG_OF_IRQ) += irq.o
@@ -10,3 +11,6 @@ obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
obj-$(CONFIG_OF_MTD) += of_mtd.o
obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
+
+CFLAGS_fdt.o = -I$(src)/../../scripts/dtc/libfdt
+CFLAGS_fdt_address.o = -I$(src)/../../scripts/dtc/libfdt
diff --git a/drivers/of/address.c b/drivers/of/address.c
index cb4242a69cd5..95351b2a112c 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -498,8 +498,7 @@ static u64 __of_translate_address(struct device_node *dev,
/* Count address cells & copy address locally */
bus->count_cells(dev, &na, &ns);
if (!OF_CHECK_COUNTS(na, ns)) {
- printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
- of_node_full_name(dev));
+ pr_debug("OF: Bad cell count for %s\n", of_node_full_name(dev));
goto bail;
}
memcpy(addr, in_addr, na * 4);
@@ -564,25 +563,6 @@ u64 of_translate_dma_address(struct device_node *dev, const __be32 *in_addr)
}
EXPORT_SYMBOL(of_translate_dma_address);
-bool of_can_translate_address(struct device_node *dev)
-{
- struct device_node *parent;
- struct of_bus *bus;
- int na, ns;
-
- parent = of_get_parent(dev);
- if (parent == NULL)
- return false;
-
- bus = of_match_bus(parent);
- bus->count_cells(dev, &na, &ns);
-
- of_node_put(parent);
-
- return OF_CHECK_COUNTS(na, ns);
-}
-EXPORT_SYMBOL(of_can_translate_address);
-
const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
unsigned int *flags)
{
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 32e969d95319..8368d96ae7b4 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -695,6 +695,25 @@ struct device_node *of_get_next_parent(struct device_node *node)
}
EXPORT_SYMBOL(of_get_next_parent);
+static struct device_node *__of_get_next_child(const struct device_node *node,
+ struct device_node *prev)
+{
+ struct device_node *next;
+
+ if (!node)
+ return NULL;
+
+ next = prev ? prev->sibling : node->child;
+ for (; next; next = next->sibling)
+ if (of_node_get(next))
+ break;
+ of_node_put(prev);
+ return next;
+}
+#define __for_each_child_of_node(parent, child) \
+ for (child = __of_get_next_child(parent, NULL); child != NULL; \
+ child = __of_get_next_child(parent, child))
+
/**
* of_get_next_child - Iterate a node childs
* @node: parent node
@@ -710,11 +729,7 @@ struct device_node *of_get_next_child(const struct device_node *node,
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
- next = prev ? prev->sibling : node->child;
- for (; next; next = next->sibling)
- if (of_node_get(next))
- break;
- of_node_put(prev);
+ next = __of_get_next_child(node, prev);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return next;
}
@@ -734,6 +749,9 @@ struct device_node *of_get_next_available_child(const struct device_node *node,
struct device_node *next;
unsigned long flags;
+ if (!node)
+ return NULL;
+
raw_spin_lock_irqsave(&devtree_lock, flags);
next = prev ? prev->sibling : node->child;
for (; next; next = next->sibling) {
@@ -771,23 +789,78 @@ struct device_node *of_get_child_by_name(const struct device_node *node,
}
EXPORT_SYMBOL(of_get_child_by_name);
+static struct device_node *__of_find_node_by_path(struct device_node *parent,
+ const char *path)
+{
+ struct device_node *child;
+ int len = strchrnul(path, '/') - path;
+
+ if (!len)
+ return NULL;
+
+ __for_each_child_of_node(parent, child) {
+ const char *name = strrchr(child->full_name, '/');
+ if (WARN(!name, "malformed device_node %s\n", child->full_name))
+ continue;
+ name++;
+ if (strncmp(path, name, len) == 0 && (strlen(name) == len))
+ return child;
+ }
+ return NULL;
+}
+
/**
* of_find_node_by_path - Find a node matching a full OF path
- * @path: The full path to match
+ * @path: Either the full path to match, or if the path does not
+ * start with '/', the name of a property of the /aliases
+ * node (an alias). In the case of an alias, the node
+ * matching the alias' value will be returned.
+ *
+ * Valid paths:
+ * /foo/bar Full path
+ * foo Valid alias
+ * foo/bar Valid alias + relative path
*
* Returns a node pointer with refcount incremented, use
* of_node_put() on it when done.
*/
struct device_node *of_find_node_by_path(const char *path)
{
- struct device_node *np = of_allnodes;
+ struct device_node *np = NULL;
+ struct property *pp;
unsigned long flags;
+ if (strcmp(path, "/") == 0)
+ return of_node_get(of_allnodes);
+
+ /* The path could begin with an alias */
+ if (*path != '/') {
+ char *p = strchrnul(path, '/');
+ int len = p - path;
+
+ /* of_aliases must not be NULL */
+ if (!of_aliases)
+ return NULL;
+
+ for_each_property_of_node(of_aliases, pp) {
+ if (strlen(pp->name) == len && !strncmp(pp->name, path, len)) {
+ np = of_find_node_by_path(pp->value);
+ break;
+ }
+ }
+ if (!np)
+ return NULL;
+ path = p;
+ }
+
+ /* Step down the tree matching path components */
raw_spin_lock_irqsave(&devtree_lock, flags);
- for (; np; np = np->allnext) {
- if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
- && of_node_get(np))
- break;
+ if (!np)
+ np = of_node_get(of_allnodes);
+ while (np && *path == '/') {
+ path++; /* Increment past '/' delimiter */
+ np = __of_find_node_by_path(np, path);
+ path = strchrnul(path, '/');
}
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
@@ -1800,7 +1873,7 @@ int of_update_property(struct device_node *np, struct property *newprop)
{
struct property **next, *oldprop;
unsigned long flags;
- int rc, found = 0;
+ int rc;
rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop);
if (rc)
@@ -1809,34 +1882,34 @@ int of_update_property(struct device_node *np, struct property *newprop)
if (!newprop->name)
return -EINVAL;
- oldprop = of_find_property(np, newprop->name, NULL);
- if (!oldprop)
- return of_add_property(np, newprop);
-
raw_spin_lock_irqsave(&devtree_lock, flags);
next = &np->properties;
- while (*next) {
+ oldprop = __of_find_property(np, newprop->name, NULL);
+ if (!oldprop) {
+ /* add the new node */
+ rc = __of_add_property(np, newprop);
+ } else while (*next) {
+ /* replace the node */
if (*next == oldprop) {
- /* found the node */
newprop->next = oldprop->next;
*next = newprop;
oldprop->next = np->deadprops;
np->deadprops = oldprop;
- found = 1;
break;
}
next = &(*next)->next;
}
raw_spin_unlock_irqrestore(&devtree_lock, flags);
- if (!found)
- return -ENODEV;
+ if (rc)
+ return rc;
/* At early boot, bail out and defer setup to of_init() */
if (!of_kset)
- return found ? 0 : -ENODEV;
+ return 0;
/* Update the sysfs attribute */
- sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
+ if (oldprop)
+ sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
__of_add_property_sysfs(np, newprop);
return 0;
@@ -2040,8 +2113,8 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
* @np: Pointer to the given device_node
* @stem: Alias stem of the given device_node
*
- * The function travels the lookup table to get alias id for the given
- * device_node and alias stem. It returns the alias id if find it.
+ * The function travels the lookup table to get the alias id for the given
+ * device_node and alias stem. It returns the alias id if found.
*/
int of_alias_get_id(struct device_node *np, const char *stem)
{
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 7a2ef7bb8022..c4cddf0cd96d 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -12,7 +12,6 @@
#include <linux/kernel.h>
#include <linux/initrd.h>
#include <linux/memblock.h>
-#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/of_reserved_mem.h>
@@ -20,62 +19,13 @@
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/slab.h>
+#include <linux/libfdt.h>
+#include <linux/debugfs.h>
+#include <linux/serial_core.h>
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */
-#ifdef CONFIG_PPC
-#include <asm/machdep.h>
-#endif /* CONFIG_PPC */
-
#include <asm/page.h>
-char *of_fdt_get_string(struct boot_param_header *blob, u32 offset)
-{
- return ((char *)blob) +
- be32_to_cpu(blob->off_dt_strings) + offset;
-}
-
-/**
- * of_fdt_get_property - Given a node in the given flat blob, return
- * the property ptr
- */
-void *of_fdt_get_property(struct boot_param_header *blob,
- unsigned long node, const char *name,
- unsigned long *size)
-{
- unsigned long p = node;
-
- do {
- u32 tag = be32_to_cpup((__be32 *)p);
- u32 sz, noff;
- const char *nstr;
-
- p += 4;
- if (tag == OF_DT_NOP)
- continue;
- if (tag != OF_DT_PROP)
- return NULL;
-
- sz = be32_to_cpup((__be32 *)p);
- noff = be32_to_cpup((__be32 *)(p + 4));
- p += 8;
- if (be32_to_cpu(blob->version) < 0x10)
- p = ALIGN(p, sz >= 8 ? 8 : 4);
-
- nstr = of_fdt_get_string(blob, noff);
- if (nstr == NULL) {
- pr_warning("Can't find property index name !\n");
- return NULL;
- }
- if (strcmp(name, nstr) == 0) {
- if (size)
- *size = sz;
- return (void *)p;
- }
- p += sz;
- p = ALIGN(p, 4);
- } while (1);
-}
-
/**
* of_fdt_is_compatible - Return true if given node from the given blob has
* compat in its compatible list
@@ -86,13 +36,14 @@ void *of_fdt_get_property(struct boot_param_header *blob,
* On match, returns a non-zero value with smaller values returned for more
* specific compatible values.
*/
-int of_fdt_is_compatible(struct boot_param_header *blob,
+int of_fdt_is_compatible(const void *blob,
unsigned long node, const char *compat)
{
const char *cp;
- unsigned long cplen, l, score = 0;
+ int cplen;
+ unsigned long l, score = 0;
- cp = of_fdt_get_property(blob, node, "compatible", &cplen);
+ cp = fdt_getprop(blob, node, "compatible", &cplen);
if (cp == NULL)
return 0;
while (cplen > 0) {
@@ -110,7 +61,7 @@ int of_fdt_is_compatible(struct boot_param_header *blob,
/**
* of_fdt_match - Return true if node matches a list of compatible values
*/
-int of_fdt_match(struct boot_param_header *blob, unsigned long node,
+int of_fdt_match(const void *blob, unsigned long node,
const char *const *compat)
{
unsigned int tmp, score = 0;
@@ -149,30 +100,29 @@ static void *unflatten_dt_alloc(void **mem, unsigned long size,
* @allnextpp: pointer to ->allnext from last allocated device_node
* @fpsize: Size of the node path up at the current depth.
*/
-static void * unflatten_dt_node(struct boot_param_header *blob,
+static void * unflatten_dt_node(void *blob,
void *mem,
- void **p,
+ int *poffset,
struct device_node *dad,
struct device_node ***allnextpp,
unsigned long fpsize)
{
+ const __be32 *p;
struct device_node *np;
struct property *pp, **prev_pp = NULL;
- char *pathp;
- u32 tag;
+ const char *pathp;
unsigned int l, allocl;
+ static int depth = 0;
+ int old_depth;
+ int offset;
int has_name = 0;
int new_format = 0;
- tag = be32_to_cpup(*p);
- if (tag != OF_DT_BEGIN_NODE) {
- pr_err("Weird tag at start of node: %x\n", tag);
+ pathp = fdt_get_name(blob, *poffset, &l);
+ if (!pathp)
return mem;
- }
- *p += 4;
- pathp = *p;
- l = allocl = strlen(pathp) + 1;
- *p = PTR_ALIGN(*p + l, 4);
+
+ allocl = l++;
/* version 0x10 has a more compact unit name here instead of the full
* path. we accumulate the full path size using "fpsize", we'll rebuild
@@ -190,7 +140,7 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
fpsize = 1;
allocl = 2;
l = 1;
- *pathp = '\0';
+ pathp = "";
} else {
/* account for '/' and path size minus terminal 0
* already in 'l'
@@ -237,32 +187,23 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
}
}
/* process properties */
- while (1) {
- u32 sz, noff;
- char *pname;
-
- tag = be32_to_cpup(*p);
- if (tag == OF_DT_NOP) {
- *p += 4;
- continue;
- }
- if (tag != OF_DT_PROP)
+ for (offset = fdt_first_property_offset(blob, *poffset);
+ (offset >= 0);
+ (offset = fdt_next_property_offset(blob, offset))) {
+ const char *pname;
+ u32 sz;
+
+ if (!(p = fdt_getprop_by_offset(blob, offset, &pname, &sz))) {
+ offset = -FDT_ERR_INTERNAL;
break;
- *p += 4;
- sz = be32_to_cpup(*p);
- noff = be32_to_cpup(*p + 4);
- *p += 8;
- if (be32_to_cpu(blob->version) < 0x10)
- *p = PTR_ALIGN(*p, sz >= 8 ? 8 : 4);
-
- pname = of_fdt_get_string(blob, noff);
+ }
+
if (pname == NULL) {
pr_info("Can't find property name in list !\n");
break;
}
if (strcmp(pname, "name") == 0)
has_name = 1;
- l = strlen(pname) + 1;
pp = unflatten_dt_alloc(&mem, sizeof(struct property),
__alignof__(struct property));
if (allnextpp) {
@@ -274,26 +215,25 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
if ((strcmp(pname, "phandle") == 0) ||
(strcmp(pname, "linux,phandle") == 0)) {
if (np->phandle == 0)
- np->phandle = be32_to_cpup((__be32*)*p);
+ np->phandle = be32_to_cpup(p);
}
/* And we process the "ibm,phandle" property
* used in pSeries dynamic device tree
* stuff */
if (strcmp(pname, "ibm,phandle") == 0)
- np->phandle = be32_to_cpup((__be32 *)*p);
- pp->name = pname;
+ np->phandle = be32_to_cpup(p);
+ pp->name = (char *)pname;
pp->length = sz;
- pp->value = *p;
+ pp->value = (__be32 *)p;
*prev_pp = pp;
prev_pp = &pp->next;
}
- *p = PTR_ALIGN((*p) + sz, 4);
}
/* with version 0x10 we may not have the name property, recreate
* it here from the unit name if absent
*/
if (!has_name) {
- char *p1 = pathp, *ps = pathp, *pa = NULL;
+ const char *p1 = pathp, *ps = pathp, *pa = NULL;
int sz;
while (*p1) {
@@ -330,19 +270,18 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
if (!np->type)
np->type = "<NULL>";
}
- while (tag == OF_DT_BEGIN_NODE || tag == OF_DT_NOP) {
- if (tag == OF_DT_NOP)
- *p += 4;
- else
- mem = unflatten_dt_node(blob, mem, p, np, allnextpp,
- fpsize);
- tag = be32_to_cpup(*p);
- }
- if (tag != OF_DT_END_NODE) {
- pr_err("Weird tag at end of node: %x\n", tag);
- return mem;
- }
- *p += 4;
+
+ old_depth = depth;
+ *poffset = fdt_next_node(blob, *poffset, &depth);
+ if (depth < 0)
+ depth = 0;
+ while (*poffset > 0 && depth > old_depth)
+ mem = unflatten_dt_node(blob, mem, poffset, np, allnextpp,
+ fpsize);
+
+ if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND)
+ pr_err("unflatten: error %d processing FDT\n", *poffset);
+
return mem;
}
@@ -358,12 +297,13 @@ static void * unflatten_dt_node(struct boot_param_header *blob,
* @dt_alloc: An allocator that provides a virtual address to memory
* for the resulting tree
*/
-static void __unflatten_device_tree(struct boot_param_header *blob,
+static void __unflatten_device_tree(void *blob,
struct device_node **mynodes,
void * (*dt_alloc)(u64 size, u64 align))
{
unsigned long size;
- void *start, *mem;
+ int start;
+ void *mem;
struct device_node **allnextp = mynodes;
pr_debug(" -> unflatten_device_tree()\n");
@@ -374,18 +314,18 @@ static void __unflatten_device_tree(struct boot_param_header *blob,
}
pr_debug("Unflattening device tree:\n");
- pr_debug("magic: %08x\n", be32_to_cpu(blob->magic));
- pr_debug("size: %08x\n", be32_to_cpu(blob->totalsize));
- pr_debug("version: %08x\n", be32_to_cpu(blob->version));
+ pr_debug("magic: %08x\n", fdt_magic(blob));
+ pr_debug("size: %08x\n", fdt_totalsize(blob));
+ pr_debug("version: %08x\n", fdt_version(blob));
- if (be32_to_cpu(blob->magic) != OF_DT_HEADER) {
+ if (fdt_check_header(blob)) {
pr_err("Invalid device tree blob header\n");
return;
}
/* First pass, scan for size */
- start = ((void *)blob) + be32_to_cpu(blob->off_dt_struct);
- size = (unsigned long)unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
+ start = 0;
+ size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0);
size = ALIGN(size, 4);
pr_debug(" size is %lx, allocating...\n", size);
@@ -399,10 +339,8 @@ static void __unflatten_device_tree(struct boot_param_header *blob,
pr_debug(" unflattening %p...\n", mem);
/* Second pass, do actual unflattening */
- start = ((void *)blob) + be32_to_cpu(blob->off_dt_struct);
+ start = 0;
unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);
- if (be32_to_cpup(start) != OF_DT_END)
- pr_warning("Weird tag at end of tree: %08x\n", be32_to_cpup(start));
if (be32_to_cpup(mem + size) != 0xdeadbeef)
pr_warning("End of tree marker overwritten: %08x\n",
be32_to_cpup(mem + size));
@@ -427,9 +365,7 @@ static void *kernel_tree_alloc(u64 size, u64 align)
void of_fdt_unflatten_tree(unsigned long *blob,
struct device_node **mynodes)
{
- struct boot_param_header *device_tree =
- (struct boot_param_header *)blob;
- __unflatten_device_tree(device_tree, mynodes, &kernel_tree_alloc);
+ __unflatten_device_tree(blob, mynodes, &kernel_tree_alloc);
}
EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
@@ -437,7 +373,7 @@ EXPORT_SYMBOL_GPL(of_fdt_unflatten_tree);
int __initdata dt_root_addr_cells;
int __initdata dt_root_size_cells;
-struct boot_param_header *initial_boot_params;
+void *initial_boot_params;
#ifdef CONFIG_OF_EARLY_FLATTREE
@@ -449,8 +385,8 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
{
int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
phys_addr_t base, size;
- unsigned long len;
- __be32 *prop;
+ int len;
+ const __be32 *prop;
int nomap, first = 1;
prop = of_get_flat_dt_prop(node, "reg", &len);
@@ -493,7 +429,7 @@ static int __init __reserved_mem_reserve_reg(unsigned long node,
*/
static int __init __reserved_mem_check_root(unsigned long node)
{
- __be32 *prop;
+ const __be32 *prop;
prop = of_get_flat_dt_prop(node, "#size-cells", NULL);
if (!prop || be32_to_cpup(prop) != dt_root_size_cells)
@@ -557,9 +493,25 @@ static int __init __fdt_scan_reserved_mem(unsigned long node, const char *uname,
*/
void __init early_init_fdt_scan_reserved_mem(void)
{
+ int n;
+ u64 base, size;
+
if (!initial_boot_params)
return;
+ /* Reserve the dtb region */
+ early_init_dt_reserve_memory_arch(__pa(initial_boot_params),
+ fdt_totalsize(initial_boot_params),
+ 0);
+
+ /* Process header /memreserve/ fields */
+ for (n = 0; ; n++) {
+ fdt_get_mem_rsv(initial_boot_params, n, &base, &size);
+ if (!size)
+ break;
+ early_init_dt_reserve_memory_arch(base, size, 0);
+ }
+
of_scan_flat_dt(__fdt_scan_reserved_mem, NULL);
fdt_init_reserved_mem();
}
@@ -578,47 +530,19 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node,
void *data),
void *data)
{
- unsigned long p = ((unsigned long)initial_boot_params) +
- be32_to_cpu(initial_boot_params->off_dt_struct);
- int rc = 0;
- int depth = -1;
-
- do {
- u32 tag = be32_to_cpup((__be32 *)p);
- const char *pathp;
-
- p += 4;
- if (tag == OF_DT_END_NODE) {
- depth--;
- continue;
- }
- if (tag == OF_DT_NOP)
- continue;
- if (tag == OF_DT_END)
- break;
- if (tag == OF_DT_PROP) {
- u32 sz = be32_to_cpup((__be32 *)p);
- p += 8;
- if (be32_to_cpu(initial_boot_params->version) < 0x10)
- p = ALIGN(p, sz >= 8 ? 8 : 4);
- p += sz;
- p = ALIGN(p, 4);
- continue;
- }
- if (tag != OF_DT_BEGIN_NODE) {
- pr_err("Invalid tag %x in flat device tree!\n", tag);
- return -EINVAL;
- }
- depth++;
- pathp = (char *)p;
- p = ALIGN(p + strlen(pathp) + 1, 4);
+ const void *blob = initial_boot_params;
+ const char *pathp;
+ int offset, rc = 0, depth = -1;
+
+ for (offset = fdt_next_node(blob, -1, &depth);
+ offset >= 0 && depth >= 0 && !rc;
+ offset = fdt_next_node(blob, offset, &depth)) {
+
+ pathp = fdt_get_name(blob, offset, NULL);
if (*pathp == '/')
pathp = kbasename(pathp);
- rc = it(p, pathp, depth, data);
- if (rc != 0)
- break;
- } while (1);
-
+ rc = it(offset, pathp, depth, data);
+ }
return rc;
}
@@ -627,14 +551,15 @@ int __init of_scan_flat_dt(int (*it)(unsigned long node,
*/
unsigned long __init of_get_flat_dt_root(void)
{
- unsigned long p = ((unsigned long)initial_boot_params) +
- be32_to_cpu(initial_boot_params->off_dt_struct);
-
- while (be32_to_cpup((__be32 *)p) == OF_DT_NOP)
- p += 4;
- BUG_ON(be32_to_cpup((__be32 *)p) != OF_DT_BEGIN_NODE);
- p += 4;
- return ALIGN(p + strlen((char *)p) + 1, 4);
+ return 0;
+}
+
+/**
+ * of_get_flat_dt_size - Return the total size of the FDT
+ */
+int __init of_get_flat_dt_size(void)
+{
+ return fdt_totalsize(initial_boot_params);
}
/**
@@ -643,10 +568,10 @@ unsigned long __init of_get_flat_dt_root(void)
* This function can be used within scan_flattened_dt callback to get
* access to properties
*/
-void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
- unsigned long *size)
+const void *__init of_get_flat_dt_prop(unsigned long node, const char *name,
+ int *size)
{
- return of_fdt_get_property(initial_boot_params, node, name, size);
+ return fdt_getprop(initial_boot_params, node, name, size);
}
/**
@@ -676,73 +601,6 @@ struct fdt_scan_status {
void *data;
};
-/**
- * fdt_scan_node_by_path - iterator for of_scan_flat_dt_by_path function
- */
-static int __init fdt_scan_node_by_path(unsigned long node, const char *uname,
- int depth, void *data)
-{
- struct fdt_scan_status *st = data;
-
- /*
- * if scan at the requested fdt node has been completed,
- * return -ENXIO to abort further scanning
- */
- if (depth <= st->depth)
- return -ENXIO;
-
- /* requested fdt node has been found, so call iterator function */
- if (st->found)
- return st->iterator(node, uname, depth, st->data);
-
- /* check if scanning automata is entering next level of fdt nodes */
- if (depth == st->depth + 1 &&
- strncmp(st->name, uname, st->namelen) == 0 &&
- uname[st->namelen] == 0) {
- st->depth += 1;
- if (st->name[st->namelen] == 0) {
- st->found = 1;
- } else {
- const char *next = st->name + st->namelen + 1;
- st->name = next;
- st->namelen = strcspn(next, "/");
- }
- return 0;
- }
-
- /* scan next fdt node */
- return 0;
-}
-
-/**
- * of_scan_flat_dt_by_path - scan flattened tree blob and call callback on each
- * child of the given path.
- * @path: path to start searching for children
- * @it: callback function
- * @data: context data pointer
- *
- * This function is used to scan the flattened device-tree starting from the
- * node given by path. It is used to extract information (like reserved
- * memory), which is required on ealy boot before we can unflatten the tree.
- */
-int __init of_scan_flat_dt_by_path(const char *path,
- int (*it)(unsigned long node, const char *name, int depth, void *data),
- void *data)
-{
- struct fdt_scan_status st = {path, 0, -1, 0, it, data};
- int ret = 0;
-
- if (initial_boot_params)
- ret = of_scan_flat_dt(fdt_scan_node_by_path, &st);
-
- if (!st.found)
- return -ENOENT;
- else if (ret == -ENXIO) /* scan has been completed */
- return 0;
- else
- return ret;
-}
-
const char * __init of_flat_dt_get_machine_name(void)
{
const char *name;
@@ -782,7 +640,7 @@ const void * __init of_flat_dt_match_machine(const void *default_match,
}
if (!best_data) {
const char *prop;
- long size;
+ int size;
pr_err("\n unrecognized device tree list:\n[ ");
@@ -811,8 +669,8 @@ const void * __init of_flat_dt_match_machine(const void *default_match,
static void __init early_init_dt_check_for_initrd(unsigned long node)
{
u64 start, end;
- unsigned long len;
- __be32 *prop;
+ int len;
+ const __be32 *prop;
pr_debug("Looking for initrd properties... ");
@@ -839,13 +697,68 @@ static inline void early_init_dt_check_for_initrd(unsigned long node)
}
#endif /* CONFIG_BLK_DEV_INITRD */
+#ifdef CONFIG_SERIAL_EARLYCON
+extern struct of_device_id __earlycon_of_table[];
+
+int __init early_init_dt_scan_chosen_serial(void)
+{
+ int offset;
+ const char *p;
+ int l;
+ const struct of_device_id *match = __earlycon_of_table;
+ const void *fdt = initial_boot_params;
+
+ offset = fdt_path_offset(fdt, "/chosen");
+ if (offset < 0)
+ offset = fdt_path_offset(fdt, "/chosen@0");
+ if (offset < 0)
+ return -ENOENT;
+
+ p = fdt_getprop(fdt, offset, "stdout-path", &l);
+ if (!p)
+ p = fdt_getprop(fdt, offset, "linux,stdout-path", &l);
+ if (!p || !l)
+ return -ENOENT;
+
+ /* Get the node specified by stdout-path */
+ offset = fdt_path_offset(fdt, p);
+ if (offset < 0)
+ return -ENODEV;
+
+ while (match->compatible) {
+ unsigned long addr;
+ if (fdt_node_check_compatible(fdt, offset, match->compatible)) {
+ match++;
+ continue;
+ }
+
+ addr = fdt_translate_address(fdt, offset);
+ if (!addr)
+ return -ENXIO;
+
+ of_setup_earlycon(addr, match->data);
+ return 0;
+ }
+ return -ENODEV;
+}
+
+static int __init setup_of_earlycon(char *buf)
+{
+ if (buf)
+ return 0;
+
+ return early_init_dt_scan_chosen_serial();
+}
+early_param("earlycon", setup_of_earlycon);
+#endif
+
/**
* early_init_dt_scan_root - fetch the top level address and size cells
*/
int __init early_init_dt_scan_root(unsigned long node, const char *uname,
int depth, void *data)
{
- __be32 *prop;
+ const __be32 *prop;
if (depth != 0)
return 0;
@@ -867,9 +780,9 @@ int __init early_init_dt_scan_root(unsigned long node, const char *uname,
return 1;
}
-u64 __init dt_mem_next_cell(int s, __be32 **cellp)
+u64 __init dt_mem_next_cell(int s, const __be32 **cellp)
{
- __be32 *p = *cellp;
+ const __be32 *p = *cellp;
*cellp = p + s;
return of_read_number(p, s);
@@ -881,9 +794,9 @@ u64 __init dt_mem_next_cell(int s, __be32 **cellp)
int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
int depth, void *data)
{
- char *type = of_get_flat_dt_prop(node, "device_type", NULL);
- __be32 *reg, *endp;
- unsigned long l;
+ const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
+ const __be32 *reg, *endp;
+ int l;
/* We are scanning "memory" nodes only */
if (type == NULL) {
@@ -891,7 +804,7 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
* The longtrail doesn't have a device_type on the
* /memory node, so look for the node called /memory@0.
*/
- if (depth != 1 || strcmp(uname, "memory@0") != 0)
+ if (!IS_ENABLED(CONFIG_PPC32) || depth != 1 || strcmp(uname, "memory@0") != 0)
return 0;
} else if (strcmp(type, "memory") != 0)
return 0;
@@ -904,7 +817,7 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
endp = reg + (l / sizeof(__be32));
- pr_debug("memory scan node %s, reg size %ld, data: %x %x %x %x,\n",
+ pr_debug("memory scan node %s, reg size %d, data: %x %x %x %x,\n",
uname, l, reg[0], reg[1], reg[2], reg[3]);
while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
@@ -927,8 +840,8 @@ int __init early_init_dt_scan_memory(unsigned long node, const char *uname,
int __init early_init_dt_scan_chosen(unsigned long node, const char *uname,
int depth, void *data)
{
- unsigned long l;
- char *p;
+ int l;
+ const char *p;
pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname);
@@ -1003,8 +916,8 @@ void * __init __weak early_init_dt_alloc_memory_arch(u64 size, u64 align)
int __init __weak early_init_dt_reserve_memory_arch(phys_addr_t base,
phys_addr_t size, bool nomap)
{
- pr_err("Reserved memory not supported, ignoring range 0x%llx - 0x%llx%s\n",
- base, size, nomap ? " (nomap)" : "");
+ pr_err("Reserved memory not supported, ignoring range 0x%pa - 0x%pa%s\n",
+ &base, &size, nomap ? " (nomap)" : "");
return -ENOSYS;
}
#endif
@@ -1018,7 +931,7 @@ bool __init early_init_dt_scan(void *params)
initial_boot_params = params;
/* check device tree validity */
- if (be32_to_cpu(initial_boot_params->magic) != OF_DT_HEADER) {
+ if (fdt_check_header(params)) {
initial_boot_params = NULL;
return false;
}
@@ -1073,9 +986,9 @@ void __init unflatten_and_copy_device_tree(void)
return;
}
- size = __be32_to_cpu(initial_boot_params->totalsize);
+ size = fdt_totalsize(initial_boot_params);
dt = early_init_dt_alloc_memory_arch(size,
- __alignof__(struct boot_param_header));
+ roundup_pow_of_two(FDT_V17_SIZE));
if (dt) {
memcpy(dt, initial_boot_params, size);
@@ -1084,4 +997,27 @@ void __init unflatten_and_copy_device_tree(void)
unflatten_device_tree();
}
+#if defined(CONFIG_DEBUG_FS) && defined(DEBUG)
+static struct debugfs_blob_wrapper flat_dt_blob;
+
+static int __init of_flat_dt_debugfs_export_fdt(void)
+{
+ struct dentry *d = debugfs_create_dir("device-tree", NULL);
+
+ if (!d)
+ return -ENOENT;
+
+ flat_dt_blob.data = initial_boot_params;
+ flat_dt_blob.size = fdt_totalsize(initial_boot_params);
+
+ d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR,
+ d, &flat_dt_blob);
+ if (!d)
+ return -ENOENT;
+
+ return 0;
+}
+module_init(of_flat_dt_debugfs_export_fdt);
+#endif
+
#endif /* CONFIG_OF_EARLY_FLATTREE */
diff --git a/drivers/of/fdt_address.c b/drivers/of/fdt_address.c
new file mode 100644
index 000000000000..8d3dc6fbdb7a
--- /dev/null
+++ b/drivers/of/fdt_address.c
@@ -0,0 +1,241 @@
+/*
+ * FDT Address translation based on u-boot fdt_support.c which in turn was
+ * based on the kernel unflattened DT address translation code.
+ *
+ * (C) Copyright 2007
+ * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
+ *
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ *
+ * 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, or (at your option)
+ * any later version.
+ */
+#include <linux/kernel.h>
+#include <linux/libfdt.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/sizes.h>
+
+/* Max address size we deal with */
+#define OF_MAX_ADDR_CELLS 4
+#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
+ (ns) > 0)
+
+/* Debug utility */
+#ifdef DEBUG
+static void __init of_dump_addr(const char *s, const __be32 *addr, int na)
+{
+ pr_debug("%s", s);
+ while(na--)
+ pr_cont(" %08x", *(addr++));
+ pr_debug("\n");
+}
+#else
+static void __init of_dump_addr(const char *s, const __be32 *addr, int na) { }
+#endif
+
+/* Callbacks for bus specific translators */
+struct of_bus {
+ void (*count_cells)(const void *blob, int parentoffset,
+ int *addrc, int *sizec);
+ u64 (*map)(__be32 *addr, const __be32 *range,
+ int na, int ns, int pna);
+ int (*translate)(__be32 *addr, u64 offset, int na);
+};
+
+/* Default translator (generic bus) */
+static void __init fdt_bus_default_count_cells(const void *blob, int parentoffset,
+ int *addrc, int *sizec)
+{
+ const __be32 *prop;
+
+ if (addrc) {
+ prop = fdt_getprop(blob, parentoffset, "#address-cells", NULL);
+ if (prop)
+ *addrc = be32_to_cpup(prop);
+ else
+ *addrc = dt_root_addr_cells;
+ }
+
+ if (sizec) {
+ prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL);
+ if (prop)
+ *sizec = be32_to_cpup(prop);
+ else
+ *sizec = dt_root_size_cells;
+ }
+}
+
+static u64 __init fdt_bus_default_map(__be32 *addr, const __be32 *range,
+ int na, int ns, int pna)
+{
+ u64 cp, s, da;
+
+ cp = of_read_number(range, na);
+ s = of_read_number(range + na + pna, ns);
+ da = of_read_number(addr, na);
+
+ pr_debug("FDT: default map, cp=%llx, s=%llx, da=%llx\n",
+ cp, s, da);
+
+ if (da < cp || da >= (cp + s))
+ return OF_BAD_ADDR;
+ return da - cp;
+}
+
+static int __init fdt_bus_default_translate(__be32 *addr, u64 offset, int na)
+{
+ u64 a = of_read_number(addr, na);
+ memset(addr, 0, na * 4);
+ a += offset;
+ if (na > 1)
+ addr[na - 2] = cpu_to_fdt32(a >> 32);
+ addr[na - 1] = cpu_to_fdt32(a & 0xffffffffu);
+
+ return 0;
+}
+
+/* Array of bus specific translators */
+static const struct of_bus of_busses[] __initconst = {
+ /* Default */
+ {
+ .count_cells = fdt_bus_default_count_cells,
+ .map = fdt_bus_default_map,
+ .translate = fdt_bus_default_translate,
+ },
+};
+
+static int __init fdt_translate_one(const void *blob, int parent,
+ const struct of_bus *bus,
+ const struct of_bus *pbus, __be32 *addr,
+ int na, int ns, int pna, const char *rprop)
+{
+ const __be32 *ranges;
+ int rlen;
+ int rone;
+ u64 offset = OF_BAD_ADDR;
+
+ ranges = fdt_getprop(blob, parent, rprop, &rlen);
+ if (!ranges)
+ return 1;
+ if (rlen == 0) {
+ offset = of_read_number(addr, na);
+ memset(addr, 0, pna * 4);
+ pr_debug("FDT: empty ranges, 1:1 translation\n");
+ goto finish;
+ }
+
+ pr_debug("FDT: walking ranges...\n");
+
+ /* Now walk through the ranges */
+ rlen /= 4;
+ rone = na + pna + ns;
+ for (; rlen >= rone; rlen -= rone, ranges += rone) {
+ offset = bus->map(addr, ranges, na, ns, pna);
+ if (offset != OF_BAD_ADDR)
+ break;
+ }
+ if (offset == OF_BAD_ADDR) {
+ pr_debug("FDT: not found !\n");
+ return 1;
+ }
+ memcpy(addr, ranges + na, 4 * pna);
+
+ finish:
+ of_dump_addr("FDT: parent translation for:", addr, pna);
+ pr_debug("FDT: with offset: %llx\n", offset);
+
+ /* Translate it into parent bus space */
+ return pbus->translate(addr, offset, pna);
+}
+
+/*
+ * Translate an address from the device-tree into a CPU physical address,
+ * this walks up the tree and applies the various bus mappings on the
+ * way.
+ *
+ * Note: We consider that crossing any level with #size-cells == 0 to mean
+ * that translation is impossible (that is we are not dealing with a value
+ * that can be mapped to a cpu physical address). This is not really specified
+ * that way, but this is traditionally the way IBM at least do things
+ */
+u64 __init fdt_translate_address(const void *blob, int node_offset)
+{
+ int parent, len;
+ const struct of_bus *bus, *pbus;
+ const __be32 *reg;
+ __be32 addr[OF_MAX_ADDR_CELLS];
+ int na, ns, pna, pns;
+ u64 result = OF_BAD_ADDR;
+
+ pr_debug("FDT: ** translation for device %s **\n",
+ fdt_get_name(blob, node_offset, NULL));
+
+ reg = fdt_getprop(blob, node_offset, "reg", &len);
+ if (!reg) {
+ pr_err("FDT: warning: device tree node '%s' has no address.\n",
+ fdt_get_name(blob, node_offset, NULL));
+ goto bail;
+ }
+
+ /* Get parent & match bus type */
+ parent = fdt_parent_offset(blob, node_offset);
+ if (parent < 0)
+ goto bail;
+ bus = &of_busses[0];
+
+ /* Cound address cells & copy address locally */
+ bus->count_cells(blob, parent, &na, &ns);
+ if (!OF_CHECK_COUNTS(na, ns)) {
+ pr_err("FDT: Bad cell count for %s\n",
+ fdt_get_name(blob, node_offset, NULL));
+ goto bail;
+ }
+ memcpy(addr, reg, na * 4);
+
+ pr_debug("FDT: bus (na=%d, ns=%d) on %s\n",
+ na, ns, fdt_get_name(blob, parent, NULL));
+ of_dump_addr("OF: translating address:", addr, na);
+
+ /* Translate */
+ for (;;) {
+ /* Switch to parent bus */
+ node_offset = parent;
+ parent = fdt_parent_offset(blob, node_offset);
+
+ /* If root, we have finished */
+ if (parent < 0) {
+ pr_debug("FDT: reached root node\n");
+ result = of_read_number(addr, na);
+ break;
+ }
+
+ /* Get new parent bus and counts */
+ pbus = &of_busses[0];
+ pbus->count_cells(blob, parent, &pna, &pns);
+ if (!OF_CHECK_COUNTS(pna, pns)) {
+ pr_err("FDT: Bad cell count for %s\n",
+ fdt_get_name(blob, node_offset, NULL));
+ break;
+ }
+
+ pr_debug("FDT: parent bus (na=%d, ns=%d) on %s\n",
+ pna, pns, fdt_get_name(blob, parent, NULL));
+
+ /* Apply bus translation */
+ if (fdt_translate_one(blob, node_offset, bus, pbus,
+ addr, na, ns, pna, "ranges"))
+ break;
+
+ /* Complete the move up one level */
+ na = pna;
+ ns = pns;
+ bus = pbus;
+
+ of_dump_addr("FDT: one level translation:", addr, na);
+ }
+ bail:
+ return result;
+}
diff --git a/drivers/of/irq.c b/drivers/of/irq.c
index 5aeb89411350..3e06a699352d 100644
--- a/drivers/of/irq.c
+++ b/drivers/of/irq.c
@@ -406,6 +406,28 @@ int of_irq_get(struct device_node *dev, int index)
}
/**
+ * of_irq_get_byname - Decode a node's IRQ and return it as a Linux irq number
+ * @dev: pointer to device tree node
+ * @name: irq name
+ *
+ * Returns Linux irq number on success, or -EPROBE_DEFER if the irq domain
+ * is not yet created, or error code in case of any other failure.
+ */
+int of_irq_get_byname(struct device_node *dev, const char *name)
+{
+ int index;
+
+ if (unlikely(!name))
+ return -EINVAL;
+
+ index = of_property_match_string(dev, "interrupt-names", name);
+ if (index < 0)
+ return index;
+
+ return of_irq_get(dev, index);
+}
+
+/**
* of_irq_count - Count the number of IRQs a node uses
* @dev: pointer to device tree node
*/
diff --git a/drivers/of/of_pci_irq.c b/drivers/of/of_pci_irq.c
index 8736bc7676c5..1710d9dc7fc2 100644
--- a/drivers/of/of_pci_irq.c
+++ b/drivers/of/of_pci_irq.c
@@ -18,8 +18,6 @@ int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq
{
struct device_node *dn, *ppnode;
struct pci_dev *ppdev;
- u32 lspec;
- __be32 lspec_be;
__be32 laddr[3];
u8 pin;
int rc;
@@ -46,7 +44,6 @@ int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq
return -ENODEV;
/* Now we walk up the PCI tree */
- lspec = pin;
for (;;) {
/* Get the pci_dev of our parent */
ppdev = pdev->bus->self;
@@ -80,14 +77,13 @@ int of_irq_parse_pci(const struct pci_dev *pdev, struct of_phandle_args *out_irq
/* We can only get here if we hit a P2P bridge with no node,
* let's do standard swizzling and try again
*/
- lspec = pci_swizzle_interrupt_pin(pdev, lspec);
+ pin = pci_swizzle_interrupt_pin(pdev, pin);
pdev = ppdev;
}
out_irq->np = ppnode;
out_irq->args_count = 1;
- out_irq->args[0] = lspec;
- lspec_be = cpu_to_be32(lspec);
+ out_irq->args[0] = pin;
laddr[0] = cpu_to_be32((pdev->bus->number << 16) | (pdev->devfn << 8));
laddr[1] = laddr[2] = cpu_to_be32(0);
return of_irq_parse_raw(laddr, out_irq);
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index daaaf935911d..632aae861375 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -95,8 +95,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
int t_len = (dt_root_addr_cells + dt_root_size_cells) * sizeof(__be32);
phys_addr_t start = 0, end = 0;
phys_addr_t base = 0, align = 0, size;
- unsigned long len;
- __be32 *prop;
+ int len;
+ const __be32 *prop;
int nomap;
int ret;
@@ -188,7 +188,7 @@ static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
if (!of_flat_dt_is_compatible(rmem->fdt_node, compat))
continue;
- if (initfn(rmem, rmem->fdt_node, rmem->name) == 0) {
+ if (initfn(rmem) == 0) {
pr_info("Reserved memory: initialized node %s, compatible id %s\n",
rmem->name, compat);
return 0;
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index e8376d646d98..92c060e58b02 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -51,10 +51,6 @@ struct platform_device *of_find_device_by_node(struct device_node *np)
}
EXPORT_SYMBOL(of_find_device_by_node);
-#if defined(CONFIG_PPC_DCR)
-#include <asm/dcr.h>
-#endif
-
#ifdef CONFIG_OF_ADDRESS
/*
* The following routines scan a subtree and registers a device for
@@ -68,66 +64,35 @@ EXPORT_SYMBOL(of_find_device_by_node);
* of_device_make_bus_id - Use the device node data to assign a unique name
* @dev: pointer to device structure that is linked to a device tree node
*
- * This routine will first try using either the dcr-reg or the reg property
- * value to derive a unique name. As a last resort it will use the node
- * name followed by a unique number.
+ * This routine will first try using the translated bus address to
+ * derive a unique name. If it cannot, then it will prepend names from
+ * parent nodes until a unique name can be derived.
*/
void of_device_make_bus_id(struct device *dev)
{
- static atomic_t bus_no_reg_magic;
struct device_node *node = dev->of_node;
const __be32 *reg;
u64 addr;
- const __be32 *addrp;
- int magic;
-#ifdef CONFIG_PPC_DCR
- /*
- * If it's a DCR based device, use 'd' for native DCRs
- * and 'D' for MMIO DCRs.
- */
- reg = of_get_property(node, "dcr-reg", NULL);
- if (reg) {
-#ifdef CONFIG_PPC_DCR_NATIVE
- dev_set_name(dev, "d%x.%s", *reg, node->name);
-#else /* CONFIG_PPC_DCR_NATIVE */
- u64 addr = of_translate_dcr_address(node, *reg, NULL);
- if (addr != OF_BAD_ADDR) {
- dev_set_name(dev, "D%llx.%s",
- (unsigned long long)addr, node->name);
+ /* Construct the name, using parent nodes if necessary to ensure uniqueness */
+ while (node->parent) {
+ /*
+ * If the address can be translated, then that is as much
+ * uniqueness as we need. Make it the first component and return
+ */
+ reg = of_get_property(node, "reg", NULL);
+ if (reg && (addr = of_translate_address(node, reg)) != OF_BAD_ADDR) {
+ dev_set_name(dev, dev_name(dev) ? "%llx.%s:%s" : "%llx.%s",
+ (unsigned long long)addr, node->name,
+ dev_name(dev));
return;
}
-#endif /* !CONFIG_PPC_DCR_NATIVE */
- }
-#endif /* CONFIG_PPC_DCR */
- /*
- * For MMIO, get the physical address
- */
- reg = of_get_property(node, "reg", NULL);
- if (reg) {
- if (of_can_translate_address(node)) {
- addr = of_translate_address(node, reg);
- } else {
- addrp = of_get_address(node, 0, NULL, NULL);
- if (addrp)
- addr = of_read_number(addrp, 1);
- else
- addr = OF_BAD_ADDR;
- }
- if (addr != OF_BAD_ADDR) {
- dev_set_name(dev, "%llx.%s",
- (unsigned long long)addr, node->name);
- return;
- }
+ /* format arguments only used if dev_name() resolves to NULL */
+ dev_set_name(dev, dev_name(dev) ? "%s:%s" : "%s",
+ strrchr(node->full_name, '/') + 1, dev_name(dev));
+ node = node->parent;
}
-
- /*
- * No BusID, use the node name and add a globally incremented
- * counter (and pray...)
- */
- magic = atomic_add_return(1, &bus_no_reg_magic);
- dev_set_name(dev, "%s.%d", node->name, magic - 1);
}
/**
@@ -149,9 +114,8 @@ struct platform_device *of_device_alloc(struct device_node *np,
return NULL;
/* count the io and irq resources */
- if (of_can_translate_address(np))
- while (of_address_to_resource(np, num_reg, &temp_res) == 0)
- num_reg++;
+ while (of_address_to_resource(np, num_reg, &temp_res) == 0)
+ num_reg++;
num_irq = of_irq_count(np);
/* Populate the resource table */
diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c
index fe70b86bcffb..077314eebb95 100644
--- a/drivers/of/selftest.c
+++ b/drivers/of/selftest.c
@@ -31,6 +31,51 @@ static struct selftest_results {
} \
}
+static void __init of_selftest_find_node_by_name(void)
+{
+ struct device_node *np;
+
+ np = of_find_node_by_path("/testcase-data");
+ selftest(np && !strcmp("/testcase-data", np->full_name),
+ "find /testcase-data failed\n");
+ of_node_put(np);
+
+ /* Test if trailing '/' works */
+ np = of_find_node_by_path("/testcase-data/");
+ selftest(!np, "trailing '/' on /testcase-data/ should fail\n");
+
+ np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
+ selftest(np && !strcmp("/testcase-data/phandle-tests/consumer-a", np->full_name),
+ "find /testcase-data/phandle-tests/consumer-a failed\n");
+ of_node_put(np);
+
+ np = of_find_node_by_path("testcase-alias");
+ selftest(np && !strcmp("/testcase-data", np->full_name),
+ "find testcase-alias failed\n");
+ of_node_put(np);
+
+ /* Test if trailing '/' works on aliases */
+ np = of_find_node_by_path("testcase-alias/");
+ selftest(!np, "trailing '/' on testcase-alias/ should fail\n");
+
+ np = of_find_node_by_path("testcase-alias/phandle-tests/consumer-a");
+ selftest(np && !strcmp("/testcase-data/phandle-tests/consumer-a", np->full_name),
+ "find testcase-alias/phandle-tests/consumer-a failed\n");
+ of_node_put(np);
+
+ np = of_find_node_by_path("/testcase-data/missing-path");
+ selftest(!np, "non-existent path returned node %s\n", np->full_name);
+ of_node_put(np);
+
+ np = of_find_node_by_path("missing-alias");
+ selftest(!np, "non-existent alias returned node %s\n", np->full_name);
+ of_node_put(np);
+
+ np = of_find_node_by_path("testcase-alias/missing-path");
+ selftest(!np, "non-existent alias with relative path returned node %s\n", np->full_name);
+ of_node_put(np);
+}
+
static void __init of_selftest_dynamic(void)
{
struct device_node *np;
@@ -431,8 +476,12 @@ static void __init of_selftest_match_node(void)
static void __init of_selftest_platform_populate(void)
{
int irq;
- struct device_node *np;
+ struct device_node *np, *child;
struct platform_device *pdev;
+ struct of_device_id match[] = {
+ { .compatible = "test-device", },
+ {}
+ };
np = of_find_node_by_path("/testcase-data");
of_platform_populate(np, of_default_bus_match_table, NULL, NULL);
@@ -440,22 +489,32 @@ static void __init of_selftest_platform_populate(void)
/* Test that a missing irq domain returns -EPROBE_DEFER */
np = of_find_node_by_path("/testcase-data/testcase-device1");
pdev = of_find_device_by_node(np);
- if (!pdev)
- selftest(0, "device 1 creation failed\n");
+ selftest(pdev, "device 1 creation failed\n");
+
irq = platform_get_irq(pdev, 0);
- if (irq != -EPROBE_DEFER)
- selftest(0, "device deferred probe failed - %d\n", irq);
+ selftest(irq == -EPROBE_DEFER, "device deferred probe failed - %d\n", irq);
/* Test that a parsing failure does not return -EPROBE_DEFER */
np = of_find_node_by_path("/testcase-data/testcase-device2");
pdev = of_find_device_by_node(np);
- if (!pdev)
- selftest(0, "device 2 creation failed\n");
+ selftest(pdev, "device 2 creation failed\n");
irq = platform_get_irq(pdev, 0);
- if (irq >= 0 || irq == -EPROBE_DEFER)
- selftest(0, "device parsing error failed - %d\n", irq);
+ selftest(irq < 0 && irq != -EPROBE_DEFER, "device parsing error failed - %d\n", irq);
- selftest(1, "passed");
+ np = of_find_node_by_path("/testcase-data/platform-tests");
+ if (!np) {
+ pr_err("No testcase data in device tree\n");
+ return;
+ }
+
+ for_each_child_of_node(np, child) {
+ struct device_node *grandchild;
+ of_platform_populate(child, match, NULL, NULL);
+ for_each_child_of_node(child, grandchild)
+ selftest(of_find_device_by_node(grandchild),
+ "Could not create device for node '%s'\n",
+ grandchild->name);
+ }
}
static int __init of_selftest(void)
@@ -470,6 +529,7 @@ static int __init of_selftest(void)
of_node_put(np);
pr_info("start of selftest - you will see error messages\n");
+ of_selftest_find_node_by_name();
of_selftest_dynamic();
of_selftest_parse_phandle_with_args();
of_selftest_property_match_string();
diff --git a/drivers/of/testcase-data/testcases.dtsi b/drivers/of/testcase-data/testcases.dtsi
index 3a5b75a8e4d7..6d8d980ac858 100644
--- a/drivers/of/testcase-data/testcases.dtsi
+++ b/drivers/of/testcase-data/testcases.dtsi
@@ -1,3 +1,4 @@
#include "tests-phandle.dtsi"
#include "tests-interrupts.dtsi"
#include "tests-match.dtsi"
+#include "tests-platform.dtsi"
diff --git a/drivers/of/testcase-data/tests-phandle.dtsi b/drivers/of/testcase-data/tests-phandle.dtsi
index 788a4c24b8f5..ce0fe083d406 100644
--- a/drivers/of/testcase-data/tests-phandle.dtsi
+++ b/drivers/of/testcase-data/tests-phandle.dtsi
@@ -1,6 +1,10 @@
/ {
- testcase-data {
+ aliases {
+ testcase-alias = &testcase;
+ };
+
+ testcase: testcase-data {
security-password = "password";
duplicate-name = "duplicate";
duplicate-name { };
diff --git a/drivers/of/testcase-data/tests-platform.dtsi b/drivers/of/testcase-data/tests-platform.dtsi
new file mode 100644
index 000000000000..eb20eeb2b062
--- /dev/null
+++ b/drivers/of/testcase-data/tests-platform.dtsi
@@ -0,0 +1,35 @@
+
+/ {
+ testcase-data {
+ platform-tests {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ test-device@0 {
+ compatible = "test-device";
+ reg = <0x0>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dev@100 {
+ compatible = "test-sub-device";
+ reg = <0x100>;
+ };
+ };
+
+ test-device@1 {
+ compatible = "test-device";
+ reg = <0x1>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ dev@100 {
+ compatible = "test-sub-device";
+ reg = <0x100>;
+ };
+ };
+ };
+ };
+};
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 7ae7aa0166b6..436a76ab4bb1 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -106,7 +106,7 @@ static bool pcie_ari_disabled;
* Given a PCI bus, returns the highest PCI bus number present in the set
* including the given PCI bus and its list of child PCI buses.
*/
-unsigned char pci_bus_max_busnr(struct pci_bus* bus)
+unsigned char pci_bus_max_busnr(struct pci_bus *bus)
{
struct pci_bus *tmp;
unsigned char max, n;
@@ -1371,7 +1371,7 @@ static void pcim_release(struct device *gendev, void *res)
pci_disable_device(dev);
}
-static struct pci_devres * get_pci_dr(struct pci_dev *pdev)
+static struct pci_devres *get_pci_dr(struct pci_dev *pdev)
{
struct pci_devres *dr, *new_dr;
@@ -1385,7 +1385,7 @@ static struct pci_devres * get_pci_dr(struct pci_dev *pdev)
return devres_get(&pdev->dev, new_dr, NULL, NULL);
}
-static struct pci_devres * find_pci_dr(struct pci_dev *pdev)
+static struct pci_devres *find_pci_dr(struct pci_dev *pdev)
{
if (pci_is_managed(pdev))
return devres_find(&pdev->dev, pcim_release, NULL, NULL);
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index c91f69b39db4..bbf78b2d6d93 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -570,6 +570,14 @@ static const struct dmi_system_id video_vendor_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"),
},
},
+ {
+ .callback = video_set_backlight_video_vendor,
+ .ident = "Acer Aspire 5741",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5741"),
+ },
+ },
{}
};
@@ -2228,7 +2236,7 @@ static int __init acer_wmi_init(void)
pr_info("Brightness must be controlled by acpi video driver\n");
} else {
pr_info("Disabling ACPI video driver\n");
- acpi_video_unregister();
+ acpi_video_unregister_backlight();
}
if (wmi_has_guid(WMID_GUID3)) {
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c
index c31aa07b3ba5..b81448b2c75d 100644
--- a/drivers/pnp/pnpacpi/core.c
+++ b/drivers/pnp/pnpacpi/core.c
@@ -30,26 +30,6 @@
static int num;
-/* We need only to blacklist devices that have already an acpi driver that
- * can't use pnp layer. We don't need to blacklist device that are directly
- * used by the kernel (PCI root, ...), as it is harmless and there were
- * already present in pnpbios. But there is an exception for devices that
- * have irqs (PIC, Timer) because we call acpi_register_gsi.
- * Finally, only devices that have a CRS method need to be in this list.
- */
-static struct acpi_device_id excluded_id_list[] __initdata = {
- {"PNP0C09", 0}, /* EC */
- {"PNP0C0F", 0}, /* Link device */
- {"PNP0000", 0}, /* PIC */
- {"PNP0100", 0}, /* Timer */
- {"", 0},
-};
-
-static inline int __init is_exclusive_device(struct acpi_device *dev)
-{
- return (!acpi_match_device_ids(dev, excluded_id_list));
-}
-
/*
* Compatible Device IDs
*/
@@ -266,7 +246,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
if (!pnpid)
return 0;
- if (is_exclusive_device(device) || !device->status.present)
+ if (!device->status.present)
return 0;
dev = pnp_alloc_dev(&pnpacpi_protocol, num, pnpid);
@@ -326,10 +306,10 @@ static acpi_status __init pnpacpi_add_device_handler(acpi_handle handle,
{
struct acpi_device *device;
- if (!acpi_bus_get_device(handle, &device))
- pnpacpi_add_device(device);
- else
+ if (acpi_bus_get_device(handle, &device))
return AE_CTRL_DEPTH;
+ if (acpi_is_pnp_device(device))
+ pnpacpi_add_device(device);
return AE_OK;
}
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index 01712cbfd92e..782e82289571 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -360,7 +360,7 @@ int pnp_check_irq(struct pnp_dev *dev, struct resource *res)
return 1;
/* check if the resource is valid */
- if (*irq < 0 || *irq > 15)
+ if (*irq > 15)
return 0;
/* check if the resource is reserved */
@@ -424,7 +424,7 @@ int pnp_check_dma(struct pnp_dev *dev, struct resource *res)
return 1;
/* check if the resource is valid */
- if (*dma < 0 || *dma == 4 || *dma > 7)
+ if (*dma == 4 || *dma > 7)
return 0;
/* check if the resource is reserved */
diff --git a/drivers/power/power_supply_core.c b/drivers/power/power_supply_core.c
index 26606641fe44..5a5a24e7d43c 100644
--- a/drivers/power/power_supply_core.c
+++ b/drivers/power/power_supply_core.c
@@ -537,7 +537,7 @@ static void psy_unregister_cooler(struct power_supply *psy)
}
#endif
-int power_supply_register(struct device *parent, struct power_supply *psy)
+int __power_supply_register(struct device *parent, struct power_supply *psy, bool ws)
{
struct device *dev;
int rc;
@@ -568,7 +568,7 @@ int power_supply_register(struct device *parent, struct power_supply *psy)
}
spin_lock_init(&psy->changed_lock);
- rc = device_init_wakeup(dev, true);
+ rc = device_init_wakeup(dev, ws);
if (rc)
goto wakeup_init_failed;
@@ -606,8 +606,19 @@ dev_set_name_failed:
success:
return rc;
}
+
+int power_supply_register(struct device *parent, struct power_supply *psy)
+{
+ return __power_supply_register(parent, psy, true);
+}
EXPORT_SYMBOL_GPL(power_supply_register);
+int power_supply_register_no_ws(struct device *parent, struct power_supply *psy)
+{
+ return __power_supply_register(parent, psy, false);
+}
+EXPORT_SYMBOL_GPL(power_supply_register_no_ws);
+
void power_supply_unregister(struct power_supply *psy)
{
cancel_work_sync(&psy->changed_work);
diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c
index d9a0770b6c73..b1cda6ffdbcc 100644
--- a/drivers/powercap/intel_rapl.c
+++ b/drivers/powercap/intel_rapl.c
@@ -951,7 +951,9 @@ static const struct x86_cpu_id rapl_ids[] = {
{ X86_VENDOR_INTEL, 6, 0x2d},/* Sandy Bridge EP */
{ X86_VENDOR_INTEL, 6, 0x37},/* Valleyview */
{ X86_VENDOR_INTEL, 6, 0x3a},/* Ivy Bridge */
- { X86_VENDOR_INTEL, 6, 0x45},/* Haswell */
+ { X86_VENDOR_INTEL, 6, 0x3c},/* Haswell */
+ { X86_VENDOR_INTEL, 6, 0x3d},/* Broadwell */
+ { X86_VENDOR_INTEL, 6, 0x45},/* Haswell ULT */
/* TODO: Add more CPU IDs after testing */
{}
};
@@ -1124,8 +1126,7 @@ err_cleanup_package:
static int rapl_check_domain(int cpu, int domain)
{
unsigned msr;
- u64 val1, val2 = 0;
- int retry = 0;
+ u64 val = 0;
switch (domain) {
case RAPL_DOMAIN_PACKAGE:
@@ -1144,26 +1145,13 @@ static int rapl_check_domain(int cpu, int domain)
pr_err("invalid domain id %d\n", domain);
return -EINVAL;
}
- if (rdmsrl_safe_on_cpu(cpu, msr, &val1))
- return -ENODEV;
-
- /* PP1/uncore/graphics domain may not be active at the time of
- * driver loading. So skip further checks.
+ /* make sure domain counters are available and contains non-zero
+ * values, otherwise skip it.
*/
- if (domain == RAPL_DOMAIN_PP1)
- return 0;
- /* energy counters roll slowly on some domains */
- while (++retry < 10) {
- usleep_range(10000, 15000);
- rdmsrl_safe_on_cpu(cpu, msr, &val2);
- if ((val1 & ENERGY_STATUS_MASK) != (val2 & ENERGY_STATUS_MASK))
- return 0;
- }
- /* if energy counter does not change, report as bad domain */
- pr_info("domain %s energy ctr %llu:%llu not working, skip\n",
- rapl_domain_names[domain], val1, val2);
+ if (rdmsrl_safe_on_cpu(cpu, msr, &val) || !val)
+ return -ENODEV;
- return -ENODEV;
+ return 0;
}
/* Detect active and valid domains for the given CPU, caller must
@@ -1180,6 +1168,9 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu)
/* use physical package id to read counters */
if (!rapl_check_domain(cpu, i))
rp->domain_map |= 1 << i;
+ else
+ pr_warn("RAPL domain %s detection failed\n",
+ rapl_domain_names[i]);
}
rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX);
if (!rp->nr_domains) {
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index 14196ea0fdf3..1918d9dff45d 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -22,11 +22,14 @@ struct read_info_sccb {
u8 rnsize; /* 10 */
u8 _reserved0[16 - 11]; /* 11-15 */
u16 ncpurl; /* 16-17 */
- u8 _reserved7[24 - 18]; /* 18-23 */
+ u16 cpuoff; /* 18-19 */
+ u8 _reserved7[24 - 20]; /* 20-23 */
u8 loadparm[8]; /* 24-31 */
u8 _reserved1[48 - 32]; /* 32-47 */
u64 facilities; /* 48-55 */
- u8 _reserved2[84 - 56]; /* 56-83 */
+ u8 _reserved2a[76 - 56]; /* 56-75 */
+ u32 ibc; /* 76-79 */
+ u8 _reserved2b[84 - 80]; /* 80-83 */
u8 fac84; /* 84 */
u8 fac85; /* 85 */
u8 _reserved3[91 - 86]; /* 86-90 */
@@ -45,6 +48,8 @@ static unsigned int sclp_con_has_linemode __initdata;
static unsigned long sclp_hsa_size;
static unsigned int sclp_max_cpu;
static struct sclp_ipl_info sclp_ipl_info;
+static unsigned char sclp_siif;
+static u32 sclp_ibc;
u64 sclp_facilities;
u8 sclp_fac84;
@@ -96,6 +101,9 @@ static int __init sclp_read_info_early(struct read_info_sccb *sccb)
static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
{
+ struct sclp_cpu_entry *cpue;
+ u16 boot_cpu_address, cpu;
+
if (sclp_read_info_early(sccb))
return;
@@ -106,6 +114,7 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
sclp_rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
sclp_rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
sclp_rzm <<= 20;
+ sclp_ibc = sccb->ibc;
if (!sccb->hcpua) {
if (MACHINE_IS_VM)
@@ -116,6 +125,15 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
sclp_max_cpu = sccb->hcpua + 1;
}
+ boot_cpu_address = stap();
+ cpue = (void *)sccb + sccb->cpuoff;
+ for (cpu = 0; cpu < sccb->ncpurl; cpue++, cpu++) {
+ if (boot_cpu_address != cpue->address)
+ continue;
+ sclp_siif = cpue->siif;
+ break;
+ }
+
/* Save IPL information */
sclp_ipl_info.is_valid = 1;
if (sccb->flags & 0x2)
@@ -148,6 +166,18 @@ unsigned int sclp_get_max_cpu(void)
return sclp_max_cpu;
}
+int sclp_has_siif(void)
+{
+ return sclp_siif;
+}
+EXPORT_SYMBOL(sclp_has_siif);
+
+unsigned int sclp_get_ibc(void)
+{
+ return sclp_ibc;
+}
+EXPORT_SYMBOL(sclp_get_ibc);
+
/*
* This function will be called after sclp_facilities_detect(), which gets
* called from early.c code. The sclp_facilities_detect() function retrieves
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
index 9b059422aacb..113874c1284b 100644
--- a/drivers/scsi/aic7xxx/aic79xx.h
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -911,7 +911,7 @@ struct vpd_config {
uint8_t length;
uint8_t revision;
uint8_t device_flags;
- uint8_t termnation_menus[2];
+ uint8_t termination_menus[2];
uint8_t fifo_threshold;
uint8_t end_tag;
uint8_t vpd_checksum;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index c0c62583b542..114ff0c6e311 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -145,16 +145,6 @@ static struct scsi_transport_template *ahc_linux_transport_template = NULL;
#endif
/*
- * Control collection of SCSI transfer statistics for the /proc filesystem.
- *
- * NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
- * NOTE: This does affect performance since it has to maintain statistics.
- */
-#ifdef CONFIG_AIC7XXX_PROC_STATS
-#define AIC7XXX_PROC_STATS
-#endif
-
-/*
* To change the default number of tagged transactions allowed per-device,
* add a line to the lilo.conf file like:
* append="aic7xxx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}"
diff --git a/drivers/sh/clk/core.c b/drivers/sh/clk/core.c
index 74727851820d..be56b22ca941 100644
--- a/drivers/sh/clk/core.c
+++ b/drivers/sh/clk/core.c
@@ -196,17 +196,11 @@ int clk_rate_table_find(struct clk *clk,
struct cpufreq_frequency_table *freq_table,
unsigned long rate)
{
- int i;
-
- for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
- unsigned long freq = freq_table[i].frequency;
+ struct cpufreq_frequency_table *pos;
- if (freq == CPUFREQ_ENTRY_INVALID)
- continue;
-
- if (freq == rate)
- return i;
- }
+ cpufreq_for_each_valid_entry(pos, freq_table)
+ if (pos->frequency == rate)
+ return pos - freq_table;
return -ENOENT;
}
@@ -575,11 +569,7 @@ long clk_round_parent(struct clk *clk, unsigned long target,
return abs(target - *best_freq);
}
- for (freq = parent->freq_table; freq->frequency != CPUFREQ_TABLE_END;
- freq++) {
- if (freq->frequency == CPUFREQ_ENTRY_INVALID)
- continue;
-
+ cpufreq_for_each_valid_entry(freq, parent->freq_table) {
if (unlikely(freq->frequency / target <= div_min - 1)) {
unsigned long freq_max;
diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c
index d87f96d9e0fa..c4ddec2b3589 100644
--- a/drivers/staging/lustre/lustre/llite/file.c
+++ b/drivers/staging/lustre/lustre/llite/file.c
@@ -2706,20 +2706,15 @@ ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FLOCK, 1);
- if (file_lock->fl_flags & FL_FLOCK) {
+ if (file_lock->fl_flags & FL_FLOCK)
LASSERT((cmd == F_SETLKW) || (cmd == F_SETLK));
- /* flocks are whole-file locks */
- flock.l_flock.end = OFFSET_MAX;
- /* For flocks owner is determined by the local file descriptor*/
- flock.l_flock.owner = (unsigned long)file_lock->fl_file;
- } else if (file_lock->fl_flags & FL_POSIX) {
- flock.l_flock.owner = (unsigned long)file_lock->fl_owner;
- flock.l_flock.start = file_lock->fl_start;
- flock.l_flock.end = file_lock->fl_end;
- } else {
+ else if (!(file_lock->fl_flags & FL_POSIX))
return -EINVAL;
- }
+
+ flock.l_flock.owner = (unsigned long)file_lock->fl_owner;
flock.l_flock.pid = file_lock->fl_pid;
+ flock.l_flock.start = file_lock->fl_start;
+ flock.l_flock.end = file_lock->fl_end;
/* Somewhat ugly workaround for svc lockd.
* lockd installs custom fl_lmops->lm_compare_owner that checks
diff --git a/drivers/staging/media/as102/as102_usb_drv.c b/drivers/staging/media/as102/as102_usb_drv.c
index e4a69454ebeb..e6f6278e97d6 100644
--- a/drivers/staging/media/as102/as102_usb_drv.c
+++ b/drivers/staging/media/as102/as102_usb_drv.c
@@ -249,7 +249,7 @@ static void as102_free_usb_stream_buffer(struct as102_dev_t *dev)
static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev)
{
- int i, ret = 0;
+ int i;
dev->stream = usb_alloc_coherent(dev->bus_adap.usb_dev,
MAX_STREAM_URB * AS102_USB_BUF_SIZE,
@@ -280,7 +280,7 @@ static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev)
dev->stream_urb[i] = urb;
}
- return ret;
+ return 0;
}
static void as102_usb_stop_stream(struct as102_dev_t *dev)
@@ -458,7 +458,6 @@ exit:
static int as102_release(struct inode *inode, struct file *file)
{
- int ret = 0;
struct as102_dev_t *dev = NULL;
dev = file->private_data;
@@ -467,7 +466,7 @@ static int as102_release(struct inode *inode, struct file *file)
kref_put(&dev->kref, as102_usb_release);
}
- return ret;
+ return 0;
}
MODULE_DEVICE_TABLE(usb, as102_usb_id_table);
diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c
index b2cd3a85166d..bbf236e842a9 100644
--- a/drivers/staging/media/bcm2048/radio-bcm2048.c
+++ b/drivers/staging/media/bcm2048/radio-bcm2048.c
@@ -737,7 +737,7 @@ static int bcm2048_set_region(struct bcm2048_device *bdev, u8 region)
int err;
u32 new_frequency = 0;
- if (region > ARRAY_SIZE(region_configs))
+ if (region >= ARRAY_SIZE(region_configs))
return -EINVAL;
mutex_lock(&bdev->mutex);
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h
index 68f6fe43a5b5..2632a806c4a8 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h
+++ b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.h
@@ -87,8 +87,6 @@ struct vpfe_fh {
struct vpfe_video_device *video;
/* Indicates whether this file handle is doing IO */
u8 io_allowed;
- /* Used to keep track priority of this instance */
- enum v4l2_priority prio;
};
void mbus_to_pix(const struct v4l2_mbus_framefmt *mbus,
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c
index acc8184c46cd..d95c427043d4 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c
@@ -415,7 +415,6 @@ static int vpfe_open(struct file *file)
video->usrs++;
/* Set io_allowed member to false */
handle->io_allowed = 0;
- v4l2_prio_open(&video->prio, &handle->prio);
handle->video = video;
file->private_data = &handle->vfh;
mutex_unlock(&video->lock);
@@ -532,8 +531,8 @@ static int vpfe_release(struct file *file)
}
/* Decrement device users counter */
video->usrs--;
- /* Close the priority */
- v4l2_prio_close(&video->prio, fh->prio);
+ v4l2_fh_del(&fh->vfh);
+ v4l2_fh_exit(&fh->vfh);
/* If this is the last file handle */
if (!video->usrs)
video->initialized = 0;
@@ -945,7 +944,7 @@ static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id)
goto unlock_out;
}
ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev, sdinfo->grp_id,
- core, s_std, std_id);
+ video, s_std, std_id);
if (ret < 0) {
v4l2_err(&vpfe_dev->v4l2_dev, "Failed to set standard\n");
video->stdid = V4L2_STD_UNKNOWN;
@@ -987,8 +986,10 @@ vpfe_enum_dv_timings(struct file *file, void *fh,
struct vpfe_device *vpfe_dev = video->vpfe_dev;
struct v4l2_subdev *subdev = video->current_ext_subdev->subdev;
+ timings->pad = 0;
+
v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_enum_dv_timings\n");
- return v4l2_subdev_call(subdev, video, enum_dv_timings, timings);
+ return v4l2_subdev_call(subdev, pad, enum_dv_timings, timings);
}
/*
@@ -1219,8 +1220,16 @@ static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count)
video->state = VPFE_VIDEO_BUFFER_QUEUED;
ret = vpfe_start_capture(video);
- if (ret)
+ if (ret) {
+ struct vpfe_cap_buffer *buf, *tmp;
+
+ vb2_buffer_done(&video->cur_frm->vb, VB2_BUF_STATE_QUEUED);
+ list_for_each_entry_safe(buf, tmp, &video->dma_queue, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+ }
goto unlock_out;
+ }
mutex_unlock(&video->lock);
@@ -1242,7 +1251,7 @@ static int vpfe_buffer_init(struct vb2_buffer *vb)
}
/* abort streaming and wait for last buffer */
-static int vpfe_stop_streaming(struct vb2_queue *vq)
+static void vpfe_stop_streaming(struct vb2_queue *vq)
{
struct vpfe_fh *fh = vb2_get_drv_priv(vq);
struct vpfe_video_device *video = fh->video;
@@ -1265,7 +1274,6 @@ static int vpfe_stop_streaming(struct vb2_queue *vq)
list_del(&video->next_frm->list);
vb2_buffer_done(&video->next_frm->vb, VB2_BUF_STATE_ERROR);
}
- return 0;
}
static void vpfe_buf_cleanup(struct vb2_buffer *vb)
@@ -1590,8 +1598,6 @@ int vpfe_video_init(struct vpfe_video_device *video, const char *name)
snprintf(video->video_dev.name, sizeof(video->video_dev.name),
"DAVINCI VIDEO %s %s", name, direction);
- /* Initialize prio member of device object */
- v4l2_prio_init(&video->prio);
spin_lock_init(&video->irqlock);
spin_lock_init(&video->dma_queue_lock);
mutex_init(&video->lock);
@@ -1600,6 +1606,7 @@ int vpfe_video_init(struct vpfe_video_device *video, const char *name)
if (ret < 0)
return ret;
+ set_bit(V4L2_FL_USE_FH_PRIO, &video->video_dev.flags);
video_set_drvdata(&video->video_dev, video);
return 0;
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.h b/drivers/staging/media/davinci_vpfe/vpfe_video.h
index ca9a70245233..1b1b6c4a56b7 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.h
+++ b/drivers/staging/media/davinci_vpfe/vpfe_video.h
@@ -102,8 +102,6 @@ struct vpfe_video_device {
* user has selected
*/
enum v4l2_memory memory;
- /* Used to keep track of state of the priority */
- struct v4l2_prio_state prio;
/* number of open instances of the channel */
u32 usrs;
/* flag to indicate whether decoder is initialized */
diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c
index afbc2e519606..40580228a6c7 100644
--- a/drivers/staging/media/dt3155v4l/dt3155v4l.c
+++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c
@@ -262,7 +262,7 @@ dt3155_buf_prepare(struct vb2_buffer *vb)
return 0;
}
-static int
+static void
dt3155_stop_streaming(struct vb2_queue *q)
{
struct dt3155_priv *pd = vb2_get_drv_priv(q);
@@ -276,7 +276,6 @@ dt3155_stop_streaming(struct vb2_queue *q)
}
spin_unlock_irq(&pd->lock);
msleep(45); /* irq hendler will stop the hardware */
- return 0;
}
static void
@@ -907,8 +906,10 @@ dt3155_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (!pd)
return -ENOMEM;
pd->vdev = video_device_alloc();
- if (!pd->vdev)
+ if (!pd->vdev) {
+ err = -ENOMEM;
goto err_video_device_alloc;
+ }
*pd->vdev = dt3155_vdev;
pci_set_drvdata(pdev, pd); /* for use in dt3155_remove() */
video_set_drvdata(pd->vdev, pd); /* for use in video_fops */
diff --git a/drivers/staging/media/go7007/go7007-v4l2.c b/drivers/staging/media/go7007/go7007-v4l2.c
index b397aa3c0f44..da7b5493e13e 100644
--- a/drivers/staging/media/go7007/go7007-v4l2.c
+++ b/drivers/staging/media/go7007/go7007-v4l2.c
@@ -516,7 +516,7 @@ static int go7007_start_streaming(struct vb2_queue *q, unsigned int count)
return ret;
}
-static int go7007_stop_streaming(struct vb2_queue *q)
+static void go7007_stop_streaming(struct vb2_queue *q)
{
struct go7007 *go = vb2_get_drv_priv(q);
unsigned long flags;
@@ -538,7 +538,6 @@ static int go7007_stop_streaming(struct vb2_queue *q)
/* Turn on Capture LED */
if (go->board_id == GO7007_BOARDID_ADS_USBAV_709)
go7007_write_addr(go, 0x3c82, 0x000d);
- return 0;
}
static struct vb2_ops go7007_video_qops = {
@@ -666,7 +665,7 @@ static int go7007_s_std(struct go7007 *go)
go->sensor_framerate = 30000;
}
- call_all(&go->v4l2_dev, core, s_std, go->std);
+ call_all(&go->v4l2_dev, video, s_std, go->std);
set_capture_size(go, NULL, 0);
return 0;
}
diff --git a/drivers/staging/media/go7007/go7007.txt b/drivers/staging/media/go7007/go7007.txt
index dc0026cff9f6..c8e5eb09d385 100644
--- a/drivers/staging/media/go7007/go7007.txt
+++ b/drivers/staging/media/go7007/go7007.txt
@@ -79,7 +79,6 @@ for custom-built kernels, the following options need to be enabled in the
kernel as built-in or modules:
CONFIG_MODULES - Enable loadable module support
- CONFIG_KMOD - Automatic kernel module loading
CONFIG_FW_LOADER - Hotplug firmware loading support
CONFIG_I2C - I2C support
CONFIG_VIDEO_DEV - Video For Linux
diff --git a/drivers/staging/media/go7007/s2250-board.c b/drivers/staging/media/go7007/s2250-board.c
index 696a80756691..eaa2b0990a1b 100644
--- a/drivers/staging/media/go7007/s2250-board.c
+++ b/drivers/staging/media/go7007/s2250-board.c
@@ -474,7 +474,6 @@ static const struct v4l2_ctrl_ops s2250_ctrl_ops = {
static const struct v4l2_subdev_core_ops s2250_core_ops = {
.log_status = s2250_log_status,
- .s_std = s2250_s_std,
};
static const struct v4l2_subdev_audio_ops s2250_audio_ops = {
@@ -482,6 +481,7 @@ static const struct v4l2_subdev_audio_ops s2250_audio_ops = {
};
static const struct v4l2_subdev_video_ops s2250_video_ops = {
+ .s_std = s2250_s_std,
.s_routing = s2250_s_video_routing,
.s_mbus_fmt = s2250_s_mbus_fmt,
};
diff --git a/drivers/staging/media/go7007/saa7134-go7007.c b/drivers/staging/media/go7007/saa7134-go7007.c
index 6e2ca338cdd9..e40f7fbfc0a5 100644
--- a/drivers/staging/media/go7007/saa7134-go7007.c
+++ b/drivers/staging/media/go7007/saa7134-go7007.c
@@ -434,11 +434,15 @@ static const struct v4l2_subdev_core_ops saa7134_go7007_core_ops = {
.g_ctrl = saa7134_go7007_g_ctrl,
.s_ctrl = saa7134_go7007_s_ctrl,
.queryctrl = saa7134_go7007_queryctrl,
+};
+
+static const struct v4l2_subdev_video_ops saa7134_go7007_video_ops = {
.s_std = saa7134_go7007_s_std,
};
static const struct v4l2_subdev_ops saa7134_go7007_sd_ops = {
.core = &saa7134_go7007_core_ops,
+ .video = &saa7134_go7007_video_ops,
};
/* --------------------------------------------------------------------------*/
diff --git a/drivers/staging/media/msi3101/sdr-msi3101.c b/drivers/staging/media/msi3101/sdr-msi3101.c
index 65d351f99da2..08d0d096b881 100644
--- a/drivers/staging/media/msi3101/sdr-msi3101.c
+++ b/drivers/staging/media/msi3101/sdr-msi3101.c
@@ -1074,14 +1074,13 @@ static int msi3101_start_streaming(struct vb2_queue *vq, unsigned int count)
return ret;
}
-static int msi3101_stop_streaming(struct vb2_queue *vq)
+static void msi3101_stop_streaming(struct vb2_queue *vq)
{
struct msi3101_state *s = vb2_get_drv_priv(vq);
- int ret;
+
dev_dbg(&s->udev->dev, "%s:\n", __func__);
- if (mutex_lock_interruptible(&s->v4l2_lock))
- return -ERESTARTSYS;
+ mutex_lock(&s->v4l2_lock);
if (s->udev)
msi3101_isoc_cleanup(s);
@@ -1090,22 +1089,15 @@ static int msi3101_stop_streaming(struct vb2_queue *vq)
/* according to tests, at least 700us delay is required */
msleep(20);
- ret = msi3101_ctrl_msg(s, CMD_STOP_STREAMING, 0);
- if (ret)
- goto err_sleep_tuner;
-
- /* sleep USB IF / ADC */
- ret = msi3101_ctrl_msg(s, CMD_WREG, 0x01000003);
- if (ret)
- goto err_sleep_tuner;
+ if (!msi3101_ctrl_msg(s, CMD_STOP_STREAMING, 0)) {
+ /* sleep USB IF / ADC */
+ msi3101_ctrl_msg(s, CMD_WREG, 0x01000003);
+ }
-err_sleep_tuner:
/* sleep tuner */
- ret = v4l2_subdev_call(s->v4l2_subdev, core, s_power, 0);
+ v4l2_subdev_call(s->v4l2_subdev, core, s_power, 0);
mutex_unlock(&s->v4l2_lock);
-
- return ret;
}
static struct vb2_ops msi3101_vb2_ops = {
diff --git a/drivers/staging/media/omap24xx/tcm825x.c b/drivers/staging/media/omap24xx/tcm825x.c
index f4dd32df2353..3367ccd1d1e8 100644
--- a/drivers/staging/media/omap24xx/tcm825x.c
+++ b/drivers/staging/media/omap24xx/tcm825x.c
@@ -89,10 +89,10 @@ static const struct tcm825x_reg rgb565 = { 0x02, TCM825X_PICFMT };
/* Our own specific controls */
#define V4L2_CID_ALC V4L2_CID_PRIVATE_BASE
-#define V4L2_CID_H_EDGE_EN V4L2_CID_PRIVATE_BASE + 1
-#define V4L2_CID_V_EDGE_EN V4L2_CID_PRIVATE_BASE + 2
-#define V4L2_CID_LENS V4L2_CID_PRIVATE_BASE + 3
-#define V4L2_CID_MAX_EXPOSURE_TIME V4L2_CID_PRIVATE_BASE + 4
+#define V4L2_CID_H_EDGE_EN (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_V_EDGE_EN (V4L2_CID_PRIVATE_BASE + 2)
+#define V4L2_CID_LENS (V4L2_CID_PRIVATE_BASE + 3)
+#define V4L2_CID_MAX_EXPOSURE_TIME (V4L2_CID_PRIVATE_BASE + 4)
#define V4L2_CID_LAST_PRIV V4L2_CID_MAX_EXPOSURE_TIME
/* Video controls */
@@ -914,8 +914,8 @@ static int __init tcm825x_init(void)
rval = i2c_add_driver(&tcm825x_i2c_driver);
if (rval)
- printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n",
- __func__);
+ pr_info("%s: failed registering " TCM825X_NAME "\n",
+ __func__);
return rval;
}
diff --git a/drivers/staging/media/omap24xx/tcm825x.h b/drivers/staging/media/omap24xx/tcm825x.h
index 9970fb1c596a..8a29636d1ad4 100644
--- a/drivers/staging/media/omap24xx/tcm825x.h
+++ b/drivers/staging/media/omap24xx/tcm825x.h
@@ -21,8 +21,8 @@
#define TCM825X_NAME "tcm825x"
-#define TCM825X_MASK(x) x & 0x00ff
-#define TCM825X_ADDR(x) (x & 0xff00) >> 8
+#define TCM825X_MASK(x) (x & 0x00ff)
+#define TCM825X_ADDR(x) ((x & 0xff00) >> 8)
/* The TCM825X I2C sensor chip has a fixed slave address of 0x3d. */
#define TCM825X_I2C_ADDR 0x3d
diff --git a/drivers/staging/media/omap4iss/Kconfig b/drivers/staging/media/omap4iss/Kconfig
index b9fe753969bd..78b0fba7047e 100644
--- a/drivers/staging/media/omap4iss/Kconfig
+++ b/drivers/staging/media/omap4iss/Kconfig
@@ -4,9 +4,3 @@ config VIDEO_OMAP4
select VIDEOBUF2_DMA_CONTIG
---help---
Driver for an OMAP 4 ISS controller.
-
-config VIDEO_OMAP4_DEBUG
- bool "OMAP 4 Camera debug messages"
- depends on VIDEO_OMAP4
- ---help---
- Enable debug messages on OMAP 4 ISS controller driver.
diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
index 61fbfcd13582..2e422dde074e 100644
--- a/drivers/staging/media/omap4iss/iss.c
+++ b/drivers/staging/media/omap4iss/iss.c
@@ -204,7 +204,7 @@ void omap4iss_configure_bridge(struct iss_device *iss,
iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL, isp5ctrl_val);
}
-#if defined(DEBUG) && defined(ISS_ISR_DEBUG)
+#ifdef ISS_ISR_DEBUG
static void iss_isr_dbg(struct iss_device *iss, u32 irqstatus)
{
static const char * const name[] = {
@@ -347,14 +347,14 @@ static irqreturn_t iss_isr(int irq, void *_iss)
omap4iss_resizer_isr(&iss->resizer,
isp_irqstatus & resizer_events);
-#if defined(DEBUG) && defined(ISS_ISR_DEBUG)
+#ifdef ISS_ISR_DEBUG
iss_isp_isr_dbg(iss, isp_irqstatus);
#endif
}
omap4iss_flush(iss);
-#if defined(DEBUG) && defined(ISS_ISR_DEBUG)
+#ifdef ISS_ISR_DEBUG
iss_isr_dbg(iss, irqstatus);
#endif
@@ -734,18 +734,17 @@ static int iss_pipeline_is_last(struct media_entity *me)
static int iss_reset(struct iss_device *iss)
{
- unsigned long timeout = 0;
+ unsigned int timeout;
iss_reg_set(iss, OMAP4_ISS_MEM_TOP, ISS_HL_SYSCONFIG,
ISS_HL_SYSCONFIG_SOFTRESET);
- while (iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_SYSCONFIG) &
- ISS_HL_SYSCONFIG_SOFTRESET) {
- if (timeout++ > 100) {
- dev_alert(iss->dev, "cannot reset ISS\n");
- return -ETIMEDOUT;
- }
- usleep_range(10, 10);
+ timeout = iss_poll_condition_timeout(
+ !(iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_SYSCONFIG) &
+ ISS_HL_SYSCONFIG_SOFTRESET), 1000, 10, 100);
+ if (timeout) {
+ dev_err(iss->dev, "ISS reset timeout\n");
+ return -ETIMEDOUT;
}
iss->crashed = 0;
@@ -754,7 +753,7 @@ static int iss_reset(struct iss_device *iss)
static int iss_isp_reset(struct iss_device *iss)
{
- unsigned long timeout = 0;
+ unsigned int timeout;
/* Fist, ensure that the ISP is IDLE (no transactions happening) */
iss_reg_update(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG,
@@ -763,29 +762,24 @@ static int iss_isp_reset(struct iss_device *iss)
iss_reg_set(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL, ISP5_CTRL_MSTANDBY);
- for (;;) {
- if (iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL) &
- ISP5_CTRL_MSTANDBY_WAIT)
- break;
- if (timeout++ > 1000) {
- dev_alert(iss->dev, "cannot set ISP5 to standby\n");
- return -ETIMEDOUT;
- }
- usleep_range(1000, 1500);
+ timeout = iss_poll_condition_timeout(
+ iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL) &
+ ISP5_CTRL_MSTANDBY_WAIT, 1000000, 1000, 1500);
+ if (timeout) {
+ dev_err(iss->dev, "ISP5 standby timeout\n");
+ return -ETIMEDOUT;
}
/* Now finally, do the reset */
iss_reg_set(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG,
ISP5_SYSCONFIG_SOFTRESET);
- timeout = 0;
- while (iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG) &
- ISP5_SYSCONFIG_SOFTRESET) {
- if (timeout++ > 1000) {
- dev_alert(iss->dev, "cannot reset ISP5\n");
- return -ETIMEDOUT;
- }
- usleep_range(1000, 1500);
+ timeout = iss_poll_condition_timeout(
+ !(iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG) &
+ ISP5_SYSCONFIG_SOFTRESET), 1000000, 1000, 1500);
+ if (timeout) {
+ dev_err(iss->dev, "ISP5 reset timeout\n");
+ return -ETIMEDOUT;
}
return 0;
diff --git a/drivers/staging/media/omap4iss/iss.h b/drivers/staging/media/omap4iss/iss.h
index 346db9233171..05cd9bf3b41f 100644
--- a/drivers/staging/media/omap4iss/iss.h
+++ b/drivers/staging/media/omap4iss/iss.h
@@ -233,4 +233,18 @@ void iss_reg_update(struct iss_device *iss, enum iss_mem_resources res,
iss_reg_write(iss, res, offset, (v & ~clr) | set);
}
+#define iss_poll_condition_timeout(cond, timeout, min_ival, max_ival) \
+({ \
+ unsigned long __timeout = jiffies + usecs_to_jiffies(timeout); \
+ unsigned int __min_ival = (min_ival); \
+ unsigned int __max_ival = (max_ival); \
+ bool __cond; \
+ while (!(__cond = (cond))) { \
+ if (time_after(jiffies, __timeout)) \
+ break; \
+ usleep_range(__min_ival, __max_ival); \
+ } \
+ !__cond; \
+})
+
#endif /* _OMAP4_ISS_H_ */
diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c
index 61fc350eb251..bf8a65726107 100644
--- a/drivers/staging/media/omap4iss/iss_csi2.c
+++ b/drivers/staging/media/omap4iss/iss_csi2.c
@@ -487,9 +487,7 @@ static void csi2_irq_status_set(struct iss_csi2_device *csi2, int enable)
*/
int omap4iss_csi2_reset(struct iss_csi2_device *csi2)
{
- u8 soft_reset_retries = 0;
- u32 reg;
- int i;
+ unsigned int timeout;
if (!csi2->available)
return -ENODEV;
@@ -500,37 +498,22 @@ int omap4iss_csi2_reset(struct iss_csi2_device *csi2)
iss_reg_set(csi2->iss, csi2->regs1, CSI2_SYSCONFIG,
CSI2_SYSCONFIG_SOFT_RESET);
- do {
- reg = iss_reg_read(csi2->iss, csi2->regs1, CSI2_SYSSTATUS)
- & CSI2_SYSSTATUS_RESET_DONE;
- if (reg == CSI2_SYSSTATUS_RESET_DONE)
- break;
- soft_reset_retries++;
- if (soft_reset_retries < 5)
- usleep_range(100, 100);
- } while (soft_reset_retries < 5);
-
- if (soft_reset_retries == 5) {
- dev_err(csi2->iss->dev,
- "CSI2: Soft reset try count exceeded!\n");
+ timeout = iss_poll_condition_timeout(
+ iss_reg_read(csi2->iss, csi2->regs1, CSI2_SYSSTATUS) &
+ CSI2_SYSSTATUS_RESET_DONE, 500, 100, 200);
+ if (timeout) {
+ dev_err(csi2->iss->dev, "CSI2: Soft reset timeout!\n");
return -EBUSY;
}
iss_reg_set(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_CFG,
CSI2_COMPLEXIO_CFG_RESET_CTRL);
- i = 100;
- do {
- reg = iss_reg_read(csi2->iss, csi2->phy->phy_regs, REGISTER1)
- & REGISTER1_RESET_DONE_CTRLCLK;
- if (reg == REGISTER1_RESET_DONE_CTRLCLK)
- break;
- usleep_range(100, 100);
- } while (--i > 0);
-
- if (i == 0) {
- dev_err(csi2->iss->dev,
- "CSI2: Reset for CSI2_96M_FCLK domain Failed!\n");
+ timeout = iss_poll_condition_timeout(
+ iss_reg_read(csi2->iss, csi2->phy->phy_regs, REGISTER1) &
+ REGISTER1_RESET_DONE_CTRLCLK, 10000, 100, 500);
+ if (timeout) {
+ dev_err(csi2->iss->dev, "CSI2: CSI2_96M_FCLK reset timeout!\n");
return -EBUSY;
}
diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h
index 878e4a3082e7..9dccdb154e1a 100644
--- a/drivers/staging/media/omap4iss/iss_video.h
+++ b/drivers/staging/media/omap4iss/iss_video.h
@@ -140,7 +140,7 @@ enum iss_video_dmaqueue_flags {
* if there was no buffer previously queued.
*/
struct iss_video_operations {
- int(*queue)(struct iss_video *video, struct iss_buffer *buffer);
+ int (*queue)(struct iss_video *video, struct iss_buffer *buffer);
};
struct iss_video {
diff --git a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
index 104ee8af79af..093df6b6ae35 100644
--- a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
+++ b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
@@ -1032,13 +1032,12 @@ err:
return ret;
}
-static int rtl2832_sdr_stop_streaming(struct vb2_queue *vq)
+static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq)
{
struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
dev_dbg(&s->udev->dev, "%s:\n", __func__);
- if (mutex_lock_interruptible(&s->v4l2_lock))
- return -ERESTARTSYS;
+ mutex_lock(&s->v4l2_lock);
rtl2832_sdr_kill_urbs(s);
rtl2832_sdr_free_urbs(s);
@@ -1053,8 +1052,6 @@ static int rtl2832_sdr_stop_streaming(struct vb2_queue *vq)
s->d->props->power_ctrl(s->d, 0);
mutex_unlock(&s->v4l2_lock);
-
- return 0;
}
static struct vb2_ops rtl2832_sdr_vb2_ops = {
diff --git a/drivers/staging/media/sn9c102/sn9c102.h b/drivers/staging/media/sn9c102/sn9c102.h
index 8a917f060503..37ca7225fcf7 100644
--- a/drivers/staging/media/sn9c102/sn9c102.h
+++ b/drivers/staging/media/sn9c102/sn9c102.h
@@ -53,7 +53,7 @@ enum sn9c102_frame_state {
};
struct sn9c102_frame_t {
- void* bufmem;
+ void *bufmem;
struct v4l2_buffer buf;
enum sn9c102_frame_state state;
struct list_head frame;
@@ -99,17 +99,17 @@ static DEFINE_MUTEX(sn9c102_sysfs_lock);
static DECLARE_RWSEM(sn9c102_dev_lock);
struct sn9c102_device {
- struct video_device* v4ldev;
+ struct video_device *v4ldev;
struct v4l2_device v4l2_dev;
enum sn9c102_bridge bridge;
struct sn9c102_sensor sensor;
- struct usb_device* usbdev;
- struct urb* urb[SN9C102_URBS];
- void* transfer_buffer[SN9C102_URBS];
- u8* control_buffer;
+ struct usb_device *usbdev;
+ struct urb *urb[SN9C102_URBS];
+ void *transfer_buffer[SN9C102_URBS];
+ u8 *control_buffer;
struct sn9c102_frame_t *frame_current, frame[SN9C102_MAX_FRAMES];
struct list_head inqueue, outqueue;
@@ -139,28 +139,28 @@ struct sn9c102_device {
/*****************************************************************************/
struct sn9c102_device*
-sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
+sn9c102_match_id(struct sn9c102_device *cam, const struct usb_device_id *id)
{
return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
}
void
-sn9c102_attach_sensor(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor)
+sn9c102_attach_sensor(struct sn9c102_device *cam,
+ const struct sn9c102_sensor *sensor)
{
memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
}
enum sn9c102_bridge
-sn9c102_get_bridge(struct sn9c102_device* cam)
+sn9c102_get_bridge(struct sn9c102_device *cam)
{
return cam->bridge;
}
-struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam)
+struct sn9c102_sensor *sn9c102_get_sensor(struct sn9c102_device *cam)
{
return &cam->sensor;
}
@@ -198,9 +198,9 @@ do { \
} \
} while (0)
#else
-# define DBG(level, fmt, args...) do {;} while(0)
-# define V4LDBG(level, name, cmd) do {;} while(0)
-# define KDBG(level, fmt, args...) do {;} while(0)
+# define DBG(level, fmt, args...) do { ; } while (0)
+# define V4LDBG(level, name, cmd) do { ; } while (0)
+# define KDBG(level, fmt, args...) do { ; } while (0)
#endif
#undef PDBG
@@ -209,6 +209,6 @@ dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \
__LINE__ , ## args)
#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
+#define PDBGG(fmt, args...) do { ; } while (0) /* placeholder */
#endif /* _SN9C102_H_ */
diff --git a/drivers/staging/media/sn9c102/sn9c102_core.c b/drivers/staging/media/sn9c102/sn9c102_core.c
index 71f594f5aa71..98b30579b0ac 100644
--- a/drivers/staging/media/sn9c102/sn9c102_core.c
+++ b/drivers/staging/media/sn9c102/sn9c102_core.c
@@ -139,15 +139,15 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device *) = {
/*****************************************************************************/
static u32
-sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
+sn9c102_request_buffers(struct sn9c102_device *cam, u32 count,
enum sn9c102_io_method io)
{
- struct v4l2_pix_format* p = &(cam->sensor.pix_format);
- struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
+ struct v4l2_pix_format *p = &(cam->sensor.pix_format);
+ struct v4l2_rect *r = &(cam->sensor.cropcap.bounds);
size_t imagesize = cam->module_param.force_munmap || io == IO_READ ?
(p->width * p->height * p->priv) / 8 :
(r->width * r->height * p->priv) / 8;
- void* buff = NULL;
+ void *buff = NULL;
u32 i;
if (count > SN9C102_MAX_FRAMES)
@@ -180,7 +180,7 @@ sn9c102_request_buffers(struct sn9c102_device* cam, u32 count,
}
-static void sn9c102_release_buffers(struct sn9c102_device* cam)
+static void sn9c102_release_buffers(struct sn9c102_device *cam)
{
if (cam->nbuffers) {
vfree(cam->frame[0].bufmem);
@@ -190,7 +190,7 @@ static void sn9c102_release_buffers(struct sn9c102_device* cam)
}
-static void sn9c102_empty_framequeues(struct sn9c102_device* cam)
+static void sn9c102_empty_framequeues(struct sn9c102_device *cam)
{
u32 i;
@@ -204,7 +204,7 @@ static void sn9c102_empty_framequeues(struct sn9c102_device* cam)
}
-static void sn9c102_requeue_outqueue(struct sn9c102_device* cam)
+static void sn9c102_requeue_outqueue(struct sn9c102_device *cam)
{
struct sn9c102_frame_t *i;
@@ -217,7 +217,7 @@ static void sn9c102_requeue_outqueue(struct sn9c102_device* cam)
}
-static void sn9c102_queue_unusedframes(struct sn9c102_device* cam)
+static void sn9c102_queue_unusedframes(struct sn9c102_device *cam)
{
unsigned long lock_flags;
u32 i;
@@ -237,11 +237,11 @@ static void sn9c102_queue_unusedframes(struct sn9c102_device* cam)
Write a sequence of count value/register pairs. Returns -1 after the first
failed write, or 0 for no errors.
*/
-int sn9c102_write_regs(struct sn9c102_device* cam, const u8 valreg[][2],
+int sn9c102_write_regs(struct sn9c102_device *cam, const u8 valreg[][2],
int count)
{
- struct usb_device* udev = cam->usbdev;
- u8* buff = cam->control_buffer;
+ struct usb_device *udev = cam->usbdev;
+ u8 *buff = cam->control_buffer;
int i, res;
for (i = 0; i < count; i++) {
@@ -273,10 +273,10 @@ int sn9c102_write_regs(struct sn9c102_device* cam, const u8 valreg[][2],
}
-int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index)
+int sn9c102_write_reg(struct sn9c102_device *cam, u8 value, u16 index)
{
- struct usb_device* udev = cam->usbdev;
- u8* buff = cam->control_buffer;
+ struct usb_device *udev = cam->usbdev;
+ u8 *buff = cam->control_buffer;
int res;
if (index >= ARRAY_SIZE(cam->reg))
@@ -299,10 +299,10 @@ int sn9c102_write_reg(struct sn9c102_device* cam, u8 value, u16 index)
/* NOTE: with the SN9C10[123] reading some registers always returns 0 */
-int sn9c102_read_reg(struct sn9c102_device* cam, u16 index)
+int sn9c102_read_reg(struct sn9c102_device *cam, u16 index)
{
- struct usb_device* udev = cam->usbdev;
- u8* buff = cam->control_buffer;
+ struct usb_device *udev = cam->usbdev;
+ u8 *buff = cam->control_buffer;
int res;
res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x00, 0xc1,
@@ -315,7 +315,7 @@ int sn9c102_read_reg(struct sn9c102_device* cam, u16 index)
}
-int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index)
+int sn9c102_pread_reg(struct sn9c102_device *cam, u16 index)
{
if (index >= ARRAY_SIZE(cam->reg))
return -1;
@@ -325,8 +325,8 @@ int sn9c102_pread_reg(struct sn9c102_device* cam, u16 index)
static int
-sn9c102_i2c_wait(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor)
+sn9c102_i2c_wait(struct sn9c102_device *cam,
+ const struct sn9c102_sensor *sensor)
{
int i, r;
@@ -346,8 +346,8 @@ sn9c102_i2c_wait(struct sn9c102_device* cam,
static int
-sn9c102_i2c_detect_read_error(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor)
+sn9c102_i2c_detect_read_error(struct sn9c102_device *cam,
+ const struct sn9c102_sensor *sensor)
{
int r , err = 0;
@@ -368,22 +368,23 @@ sn9c102_i2c_detect_read_error(struct sn9c102_device* cam,
static int
-sn9c102_i2c_detect_write_error(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor)
+sn9c102_i2c_detect_write_error(struct sn9c102_device *cam,
+ const struct sn9c102_sensor *sensor)
{
int r;
+
r = sn9c102_read_reg(cam, 0x08);
return (r < 0 || (r >= 0 && (r & 0x08))) ? -EIO : 0;
}
int
-sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor, u8 data0,
+sn9c102_i2c_try_raw_read(struct sn9c102_device *cam,
+ const struct sn9c102_sensor *sensor, u8 data0,
u8 data1, u8 n, u8 buffer[])
{
- struct usb_device* udev = cam->usbdev;
- u8* data = cam->control_buffer;
+ struct usb_device *udev = cam->usbdev;
+ u8 *data = cam->control_buffer;
int i = 0, err = 0, res;
/* Write cycle */
@@ -437,12 +438,12 @@ sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
int
-sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor, u8 n, u8 data0,
+sn9c102_i2c_try_raw_write(struct sn9c102_device *cam,
+ const struct sn9c102_sensor *sensor, u8 n, u8 data0,
u8 data1, u8 data2, u8 data3, u8 data4, u8 data5)
{
- struct usb_device* udev = cam->usbdev;
- u8* data = cam->control_buffer;
+ struct usb_device *udev = cam->usbdev;
+ u8 *data = cam->control_buffer;
int err = 0, res;
/* Write cycle. It usually is address + value */
@@ -476,16 +477,16 @@ sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
int
-sn9c102_i2c_try_read(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor, u8 address)
+sn9c102_i2c_try_read(struct sn9c102_device *cam,
+ const struct sn9c102_sensor *sensor, u8 address)
{
return sn9c102_i2c_try_raw_read(cam, sensor, sensor->i2c_slave_id,
address, 1, NULL);
}
-static int sn9c102_i2c_try_write(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor,
+static int sn9c102_i2c_try_write(struct sn9c102_device *cam,
+ const struct sn9c102_sensor *sensor,
u8 address, u8 value)
{
return sn9c102_i2c_try_raw_write(cam, sensor, 3,
@@ -494,20 +495,20 @@ static int sn9c102_i2c_try_write(struct sn9c102_device* cam,
}
-int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address)
+int sn9c102_i2c_read(struct sn9c102_device *cam, u8 address)
{
return sn9c102_i2c_try_read(cam, &cam->sensor, address);
}
-int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
+int sn9c102_i2c_write(struct sn9c102_device *cam, u8 address, u8 value)
{
return sn9c102_i2c_try_write(cam, &cam->sensor, address, value);
}
/*****************************************************************************/
-static size_t sn9c102_sof_length(struct sn9c102_device* cam)
+static size_t sn9c102_sof_length(struct sn9c102_device *cam)
{
switch (cam->bridge) {
case BRIDGE_SN9C101:
@@ -525,7 +526,7 @@ static size_t sn9c102_sof_length(struct sn9c102_device* cam)
static void*
-sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
+sn9c102_find_sof_header(struct sn9c102_device *cam, void *mem, size_t len)
{
static const char marker[6] = {0xff, 0xff, 0x00, 0xc4, 0xc4, 0x96};
const char *m = mem;
@@ -547,7 +548,7 @@ sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
}
/* Search for the SOF marker (fixed part) in the header */
- for (j = 0, b=cam->sof.bytesread; j+b < sizeof(marker); j++) {
+ for (j = 0, b = cam->sof.bytesread; j+b < sizeof(marker); j++) {
if (unlikely(i+j == len))
return NULL;
if (*(m+i+j) == marker[cam->sof.bytesread]) {
@@ -570,7 +571,7 @@ sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
static void*
-sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
+sn9c102_find_eof_header(struct sn9c102_device *cam, void *mem, size_t len)
{
static const u8 eof_header[4][4] = {
{0x00, 0x00, 0x00, 0x00},
@@ -600,7 +601,7 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
static void
-sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f)
+sn9c102_write_jpegheader(struct sn9c102_device *cam, struct sn9c102_frame_t *f)
{
static const u8 jpeg_header[589] = {
0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x06, 0x04, 0x05,
@@ -687,8 +688,8 @@ sn9c102_write_jpegheader(struct sn9c102_device* cam, struct sn9c102_frame_t* f)
static void sn9c102_urb_complete(struct urb *urb)
{
- struct sn9c102_device* cam = urb->context;
- struct sn9c102_frame_t** f;
+ struct sn9c102_device *cam = urb->context;
+ struct sn9c102_frame_t **f;
size_t imagesize, soflen;
u8 i;
int err = 0;
@@ -787,7 +788,7 @@ end_of_frame:
b = (*f)->buf.bytesused;
(*f)->state = F_DONE;
- (*f)->buf.sequence= ++cam->frame_count;
+ (*f)->buf.sequence = ++cam->frame_count;
spin_lock(&cam->queue_lock);
list_move_tail(&(*f)->frame,
@@ -796,7 +797,7 @@ end_of_frame:
(*f) = list_entry(
cam->inqueue.next,
struct sn9c102_frame_t,
- frame );
+ frame);
else
(*f) = NULL;
spin_unlock(&cam->queue_lock);
@@ -883,11 +884,11 @@ resubmit_urb:
}
-static int sn9c102_start_transfer(struct sn9c102_device* cam)
+static int sn9c102_start_transfer(struct sn9c102_device *cam)
{
struct usb_device *udev = cam->usbdev;
- struct urb* urb;
- struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
+ struct urb *urb;
+ struct usb_host_interface *altsetting = usb_altnum_to_altsetting(
usb_ifnum_to_if(udev, 0),
SN9C102_ALTERNATE_SETTING);
const unsigned int psz = le16_to_cpu(altsetting->
@@ -971,7 +972,7 @@ free_buffers:
}
-static int sn9c102_stop_transfer(struct sn9c102_device* cam)
+static int sn9c102_stop_transfer(struct sn9c102_device *cam)
{
struct usb_device *udev = cam->usbdev;
s8 i;
@@ -994,7 +995,7 @@ static int sn9c102_stop_transfer(struct sn9c102_device* cam)
}
-static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
+static int sn9c102_stream_interrupt(struct sn9c102_device *cam)
{
cam->stream = STREAM_INTERRUPT;
wait_event_timeout(cam->wait_stream,
@@ -1017,10 +1018,10 @@ static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
/*****************************************************************************/
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count)
+static u16 sn9c102_strtou16(const char *buff, size_t len, ssize_t *count)
{
char str[7];
- char* endp;
+ char *endp;
unsigned long val;
if (len < 6) {
@@ -1048,10 +1049,10 @@ static u16 sn9c102_strtou16(const char* buff, size_t len, ssize_t* count)
NOTE 2: buffers are PAGE_SIZE long
*/
-static ssize_t sn9c102_show_reg(struct device* cd,
- struct device_attribute *attr, char* buf)
+static ssize_t sn9c102_show_reg(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
- struct sn9c102_device* cam;
+ struct sn9c102_device *cam;
ssize_t count;
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
@@ -1072,10 +1073,10 @@ static ssize_t sn9c102_show_reg(struct device* cd,
static ssize_t
-sn9c102_store_reg(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
+sn9c102_store_reg(struct device *cd, struct device_attribute *attr,
+ const char *buf, size_t len)
{
- struct sn9c102_device* cam;
+ struct sn9c102_device *cam;
u16 index;
ssize_t count;
@@ -1105,10 +1106,10 @@ sn9c102_store_reg(struct device* cd, struct device_attribute *attr,
}
-static ssize_t sn9c102_show_val(struct device* cd,
- struct device_attribute *attr, char* buf)
+static ssize_t sn9c102_show_val(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
- struct sn9c102_device* cam;
+ struct sn9c102_device *cam;
ssize_t count;
int val;
@@ -1138,10 +1139,10 @@ static ssize_t sn9c102_show_val(struct device* cd,
static ssize_t
-sn9c102_store_val(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
+sn9c102_store_val(struct device *cd, struct device_attribute *attr,
+ const char *buf, size_t len)
{
- struct sn9c102_device* cam;
+ struct sn9c102_device *cam;
u16 value;
ssize_t count;
int err;
@@ -1177,10 +1178,10 @@ sn9c102_store_val(struct device* cd, struct device_attribute *attr,
}
-static ssize_t sn9c102_show_i2c_reg(struct device* cd,
- struct device_attribute *attr, char* buf)
+static ssize_t sn9c102_show_i2c_reg(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
- struct sn9c102_device* cam;
+ struct sn9c102_device *cam;
ssize_t count;
if (mutex_lock_interruptible(&sn9c102_sysfs_lock))
@@ -1203,10 +1204,10 @@ static ssize_t sn9c102_show_i2c_reg(struct device* cd,
static ssize_t
-sn9c102_store_i2c_reg(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
+sn9c102_store_i2c_reg(struct device *cd, struct device_attribute *attr,
+ const char *buf, size_t len)
{
- struct sn9c102_device* cam;
+ struct sn9c102_device *cam;
u16 index;
ssize_t count;
@@ -1236,10 +1237,10 @@ sn9c102_store_i2c_reg(struct device* cd, struct device_attribute *attr,
}
-static ssize_t sn9c102_show_i2c_val(struct device* cd,
- struct device_attribute *attr, char* buf)
+static ssize_t sn9c102_show_i2c_val(struct device *cd,
+ struct device_attribute *attr, char *buf)
{
- struct sn9c102_device* cam;
+ struct sn9c102_device *cam;
ssize_t count;
int val;
@@ -1274,10 +1275,10 @@ static ssize_t sn9c102_show_i2c_val(struct device* cd,
static ssize_t
-sn9c102_store_i2c_val(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
+sn9c102_store_i2c_val(struct device *cd, struct device_attribute *attr,
+ const char *buf, size_t len)
{
- struct sn9c102_device* cam;
+ struct sn9c102_device *cam;
u16 value;
ssize_t count;
int err;
@@ -1319,10 +1320,10 @@ sn9c102_store_i2c_val(struct device* cd, struct device_attribute *attr,
static ssize_t
-sn9c102_store_green(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
+sn9c102_store_green(struct device *cd, struct device_attribute *attr,
+ const char *buf, size_t len)
{
- struct sn9c102_device* cam;
+ struct sn9c102_device *cam;
enum sn9c102_bridge bridge;
ssize_t res = 0;
u16 value;
@@ -1350,7 +1351,8 @@ sn9c102_store_green(struct device* cd, struct device_attribute *attr,
case BRIDGE_SN9C102:
if (value > 0x0f)
return -EINVAL;
- if ((res = sn9c102_store_reg(cd, attr, "0x11", 4)) >= 0)
+ res = sn9c102_store_reg(cd, attr, "0x11", 4);
+ if (res >= 0)
res = sn9c102_store_val(cd, attr, buf, len);
break;
case BRIDGE_SN9C103:
@@ -1358,7 +1360,8 @@ sn9c102_store_green(struct device* cd, struct device_attribute *attr,
case BRIDGE_SN9C120:
if (value > 0x7f)
return -EINVAL;
- if ((res = sn9c102_store_reg(cd, attr, "0x07", 4)) >= 0)
+ res = sn9c102_store_reg(cd, attr, "0x07", 4);
+ if (res >= 0)
res = sn9c102_store_val(cd, attr, buf, len);
break;
}
@@ -1368,8 +1371,8 @@ sn9c102_store_green(struct device* cd, struct device_attribute *attr,
static ssize_t
-sn9c102_store_blue(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
+sn9c102_store_blue(struct device *cd, struct device_attribute *attr,
+ const char *buf, size_t len)
{
ssize_t res = 0;
u16 value;
@@ -1379,7 +1382,8 @@ sn9c102_store_blue(struct device* cd, struct device_attribute *attr,
if (!count || value > 0x7f)
return -EINVAL;
- if ((res = sn9c102_store_reg(cd, attr, "0x06", 4)) >= 0)
+ res = sn9c102_store_reg(cd, attr, "0x06", 4);
+ if (res >= 0)
res = sn9c102_store_val(cd, attr, buf, len);
return res;
@@ -1387,8 +1391,8 @@ sn9c102_store_blue(struct device* cd, struct device_attribute *attr,
static ssize_t
-sn9c102_store_red(struct device* cd, struct device_attribute *attr,
- const char* buf, size_t len)
+sn9c102_store_red(struct device *cd, struct device_attribute *attr,
+ const char *buf, size_t len)
{
ssize_t res = 0;
u16 value;
@@ -1397,19 +1401,19 @@ sn9c102_store_red(struct device* cd, struct device_attribute *attr,
value = sn9c102_strtou16(buf, len, &count);
if (!count || value > 0x7f)
return -EINVAL;
-
- if ((res = sn9c102_store_reg(cd, attr, "0x05", 4)) >= 0)
+ res = sn9c102_store_reg(cd, attr, "0x05", 4);
+ if (res >= 0)
res = sn9c102_store_val(cd, attr, buf, len);
return res;
}
-static ssize_t sn9c102_show_frame_header(struct device* cd,
+static ssize_t sn9c102_show_frame_header(struct device *cd,
struct device_attribute *attr,
- char* buf)
+ char *buf)
{
- struct sn9c102_device* cam;
+ struct sn9c102_device *cam;
ssize_t count;
cam = video_get_drvdata(container_of(cd, struct video_device, dev));
@@ -1437,7 +1441,7 @@ static DEVICE_ATTR(red, S_IWUSR, NULL, sn9c102_store_red);
static DEVICE_ATTR(frame_header, S_IRUGO, sn9c102_show_frame_header, NULL);
-static int sn9c102_create_sysfs(struct sn9c102_device* cam)
+static int sn9c102_create_sysfs(struct sn9c102_device *cam)
{
struct device *dev = &(cam->v4ldev->dev);
int err = 0;
@@ -1498,7 +1502,7 @@ err_out:
/*****************************************************************************/
static int
-sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix)
+sn9c102_set_pix_format(struct sn9c102_device *cam, struct v4l2_pix_format *pix)
{
int err = 0;
@@ -1538,8 +1542,8 @@ sn9c102_set_pix_format(struct sn9c102_device* cam, struct v4l2_pix_format* pix)
static int
-sn9c102_set_compression(struct sn9c102_device* cam,
- struct v4l2_jpegcompression* compression)
+sn9c102_set_compression(struct sn9c102_device *cam,
+ struct v4l2_jpegcompression *compression)
{
int i, err = 0;
@@ -1586,7 +1590,7 @@ sn9c102_set_compression(struct sn9c102_device* cam,
}
-static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
+static int sn9c102_set_scale(struct sn9c102_device *cam, u8 scale)
{
u8 r = 0;
int err = 0;
@@ -1609,9 +1613,9 @@ static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)
}
-static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
+static int sn9c102_set_crop(struct sn9c102_device *cam, struct v4l2_rect *rect)
{
- struct sn9c102_sensor* s = &cam->sensor;
+ struct sn9c102_sensor *s = &cam->sensor;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
v_start = (u8)(rect->top - s->cropcap.bounds.top),
h_size = (u8)(rect->width / 16),
@@ -1632,12 +1636,12 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
}
-static int sn9c102_init(struct sn9c102_device* cam)
+static int sn9c102_init(struct sn9c102_device *cam)
{
- struct sn9c102_sensor* s = &cam->sensor;
+ struct sn9c102_sensor *s = &cam->sensor;
struct v4l2_control ctrl;
struct v4l2_queryctrl *qctrl;
- struct v4l2_rect* rect;
+ struct v4l2_rect *rect;
u8 i = 0;
int err = 0;
@@ -1669,7 +1673,7 @@ static int sn9c102_init(struct sn9c102_device* cam)
cam->bridge == BRIDGE_SN9C102 ||
cam->bridge == BRIDGE_SN9C103) {
if (s->pix_format.pixelformat == V4L2_PIX_FMT_JPEG)
- s->pix_format.pixelformat= V4L2_PIX_FMT_SBGGR8;
+ s->pix_format.pixelformat = V4L2_PIX_FMT_SBGGR8;
cam->compression.quality = cam->reg[0x17] & 0x01 ?
0 : 1;
} else {
@@ -1761,7 +1765,7 @@ static void sn9c102_release_resources(struct kref *kref)
static int sn9c102_open(struct file *filp)
{
- struct sn9c102_device* cam;
+ struct sn9c102_device *cam;
int err = 0;
/*
@@ -1873,7 +1877,7 @@ out:
static int sn9c102_release(struct file *filp)
{
- struct sn9c102_device* cam;
+ struct sn9c102_device *cam;
down_write(&sn9c102_dev_lock);
@@ -1895,10 +1899,10 @@ static int sn9c102_release(struct file *filp)
static ssize_t
-sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
+sn9c102_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
struct sn9c102_device *cam = video_drvdata(filp);
- struct sn9c102_frame_t* f, * i;
+ struct sn9c102_frame_t *f, *i;
unsigned long lock_flags;
long timeout;
int err = 0;
@@ -1927,7 +1931,7 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
}
if (cam->io == IO_NONE) {
- if (!sn9c102_request_buffers(cam,cam->nreadbuffers, IO_READ)) {
+ if (!sn9c102_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
DBG(1, "read() failed, not enough memory");
mutex_unlock(&cam->fileop_mutex);
return -ENOMEM;
@@ -1954,17 +1958,17 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
}
if (!cam->module_param.frame_timeout) {
err = wait_event_interruptible
- ( cam->wait_frame,
+ (cam->wait_frame,
(!list_empty(&cam->outqueue)) ||
(cam->state & DEV_DISCONNECTED) ||
- (cam->state & DEV_MISCONFIGURED) );
+ (cam->state & DEV_MISCONFIGURED));
if (err) {
mutex_unlock(&cam->fileop_mutex);
return err;
}
} else {
timeout = wait_event_interruptible_timeout
- ( cam->wait_frame,
+ (cam->wait_frame,
(!list_empty(&cam->outqueue)) ||
(cam->state & DEV_DISCONNECTED) ||
(cam->state & DEV_MISCONFIGURED),
@@ -2024,7 +2028,7 @@ exit:
static unsigned int sn9c102_poll(struct file *filp, poll_table *wait)
{
struct sn9c102_device *cam = video_drvdata(filp);
- struct sn9c102_frame_t* f;
+ struct sn9c102_frame_t *f;
unsigned long lock_flags;
unsigned int mask = 0;
@@ -2076,17 +2080,17 @@ error:
}
-static void sn9c102_vm_open(struct vm_area_struct* vma)
+static void sn9c102_vm_open(struct vm_area_struct *vma)
{
- struct sn9c102_frame_t* f = vma->vm_private_data;
+ struct sn9c102_frame_t *f = vma->vm_private_data;
f->vma_use_count++;
}
-static void sn9c102_vm_close(struct vm_area_struct* vma)
+static void sn9c102_vm_close(struct vm_area_struct *vma)
{
/* NOTE: buffers are not freed here */
- struct sn9c102_frame_t* f = vma->vm_private_data;
+ struct sn9c102_frame_t *f = vma->vm_private_data;
f->vma_use_count--;
}
@@ -2097,7 +2101,7 @@ static const struct vm_operations_struct sn9c102_vm_ops = {
};
-static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
+static int sn9c102_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct sn9c102_device *cam = video_drvdata(filp);
unsigned long size = vma->vm_end - vma->vm_start,
@@ -2166,7 +2170,7 @@ static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma)
/*****************************************************************************/
static int
-sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_querycap(struct sn9c102_device *cam, void __user *arg)
{
struct v4l2_capability cap = {
.driver = "sn9c102",
@@ -2188,7 +2192,7 @@ sn9c102_vidioc_querycap(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_enuminput(struct sn9c102_device *cam, void __user *arg)
{
struct v4l2_input i;
@@ -2211,7 +2215,7 @@ sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_g_input(struct sn9c102_device *cam, void __user *arg)
{
int index = 0;
@@ -2223,7 +2227,7 @@ sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_s_input(struct sn9c102_device *cam, void __user *arg)
{
int index;
@@ -2238,9 +2242,9 @@ sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_query_ctrl(struct sn9c102_device *cam, void __user *arg)
{
- struct sn9c102_sensor* s = &cam->sensor;
+ struct sn9c102_sensor *s = &cam->sensor;
struct v4l2_queryctrl qc;
u8 i;
@@ -2260,9 +2264,9 @@ sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_g_ctrl(struct sn9c102_device *cam, void __user *arg)
{
- struct sn9c102_sensor* s = &cam->sensor;
+ struct sn9c102_sensor *s = &cam->sensor;
struct v4l2_control ctrl;
int err = 0;
u8 i;
@@ -2295,9 +2299,9 @@ exit:
static int
-sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_s_ctrl(struct sn9c102_device *cam, void __user *arg)
{
- struct sn9c102_sensor* s = &cam->sensor;
+ struct sn9c102_sensor *s = &cam->sensor;
struct v4l2_control ctrl;
u8 i;
int err = 0;
@@ -2335,9 +2339,9 @@ sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_cropcap(struct sn9c102_device *cam, void __user *arg)
{
- struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
+ struct v4l2_cropcap *cc = &(cam->sensor.cropcap);
cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
cc->pixelaspect.numerator = 1;
@@ -2351,9 +2355,9 @@ sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_g_crop(struct sn9c102_device *cam, void __user *arg)
{
- struct sn9c102_sensor* s = &cam->sensor;
+ struct sn9c102_sensor *s = &cam->sensor;
struct v4l2_crop crop = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
};
@@ -2368,13 +2372,13 @@ sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_s_crop(struct sn9c102_device *cam, void __user *arg)
{
- struct sn9c102_sensor* s = &cam->sensor;
+ struct sn9c102_sensor *s = &cam->sensor;
struct v4l2_crop crop;
- struct v4l2_rect* rect;
- struct v4l2_rect* bounds = &(s->cropcap.bounds);
- struct v4l2_pix_format* pix_format = &(s->pix_format);
+ struct v4l2_rect *rect;
+ struct v4l2_rect *bounds = &(s->cropcap.bounds);
+ struct v4l2_pix_format *pix_format = &(s->pix_format);
u8 scale;
const enum sn9c102_stream_state stream = cam->stream;
const u32 nbuffers = cam->nbuffers;
@@ -2482,7 +2486,7 @@ sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_enum_framesizes(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_enum_framesizes(struct sn9c102_device *cam, void __user *arg)
{
struct v4l2_frmsizeenum frmsize;
@@ -2523,7 +2527,7 @@ sn9c102_vidioc_enum_framesizes(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_enum_fmt(struct sn9c102_device *cam, void __user *arg)
{
struct v4l2_fmtdesc fmtd;
@@ -2565,10 +2569,10 @@ sn9c102_vidioc_enum_fmt(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_g_fmt(struct sn9c102_device *cam, void __user *arg)
{
struct v4l2_format format;
- struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
+ struct v4l2_pix_format *pfmt = &(cam->sensor.pix_format);
if (copy_from_user(&format, arg, sizeof(format)))
return -EFAULT;
@@ -2593,14 +2597,14 @@ sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
- void __user * arg)
+sn9c102_vidioc_try_s_fmt(struct sn9c102_device *cam, unsigned int cmd,
+ void __user *arg)
{
- struct sn9c102_sensor* s = &cam->sensor;
+ struct sn9c102_sensor *s = &cam->sensor;
struct v4l2_format format;
- struct v4l2_pix_format* pix;
- struct v4l2_pix_format* pfmt = &(s->pix_format);
- struct v4l2_rect* bounds = &(s->cropcap.bounds);
+ struct v4l2_pix_format *pix;
+ struct v4l2_pix_format *pfmt = &(s->pix_format);
+ struct v4l2_rect *bounds = &(s->cropcap.bounds);
struct v4l2_rect rect;
u8 scale;
const enum sn9c102_stream_state stream = cam->stream;
@@ -2742,7 +2746,7 @@ sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
static int
-sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_g_jpegcomp(struct sn9c102_device *cam, void __user *arg)
{
if (copy_to_user(arg, &cam->compression, sizeof(cam->compression)))
return -EFAULT;
@@ -2752,7 +2756,7 @@ sn9c102_vidioc_g_jpegcomp(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_s_jpegcomp(struct sn9c102_device *cam, void __user *arg)
{
struct v4l2_jpegcompression jc;
const enum sn9c102_stream_state stream = cam->stream;
@@ -2788,7 +2792,7 @@ sn9c102_vidioc_s_jpegcomp(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_reqbufs(struct sn9c102_device *cam, void __user *arg)
{
struct v4l2_requestbuffers rb;
u32 i;
@@ -2839,7 +2843,7 @@ sn9c102_vidioc_reqbufs(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_querybuf(struct sn9c102_device *cam, void __user *arg)
{
struct v4l2_buffer b;
@@ -2868,7 +2872,7 @@ sn9c102_vidioc_querybuf(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_qbuf(struct sn9c102_device *cam, void __user *arg)
{
struct v4l2_buffer b;
unsigned long lock_flags;
@@ -2896,8 +2900,8 @@ sn9c102_vidioc_qbuf(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
- void __user * arg)
+sn9c102_vidioc_dqbuf(struct sn9c102_device *cam, struct file *filp,
+ void __user *arg)
{
struct v4l2_buffer b;
struct sn9c102_frame_t *f;
@@ -2918,20 +2922,20 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
return -EAGAIN;
if (!cam->module_param.frame_timeout) {
err = wait_event_interruptible
- ( cam->wait_frame,
+ (cam->wait_frame,
(!list_empty(&cam->outqueue)) ||
(cam->state & DEV_DISCONNECTED) ||
- (cam->state & DEV_MISCONFIGURED) );
+ (cam->state & DEV_MISCONFIGURED));
if (err)
return err;
} else {
timeout = wait_event_interruptible_timeout
- ( cam->wait_frame,
+ (cam->wait_frame,
(!list_empty(&cam->outqueue)) ||
(cam->state & DEV_DISCONNECTED) ||
(cam->state & DEV_MISCONFIGURED),
cam->module_param.frame_timeout *
- 1000 * msecs_to_jiffies(1) );
+ 1000 * msecs_to_jiffies(1));
if (timeout < 0)
return timeout;
else if (timeout == 0 &&
@@ -2967,7 +2971,7 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
static int
-sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_streamon(struct sn9c102_device *cam, void __user *arg)
{
int type;
@@ -2986,7 +2990,7 @@ sn9c102_vidioc_streamon(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_streamoff(struct sn9c102_device *cam, void __user *arg)
{
int type, err;
@@ -3011,7 +3015,7 @@ sn9c102_vidioc_streamoff(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_g_parm(struct sn9c102_device *cam, void __user *arg)
{
struct v4l2_streamparm sp;
@@ -3032,7 +3036,7 @@ sn9c102_vidioc_g_parm(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_s_parm(struct sn9c102_device *cam, void __user *arg)
{
struct v4l2_streamparm sp;
@@ -3060,7 +3064,7 @@ sn9c102_vidioc_s_parm(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_enumaudio(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_enumaudio(struct sn9c102_device *cam, void __user *arg)
{
struct v4l2_audio audio;
@@ -3085,7 +3089,7 @@ sn9c102_vidioc_enumaudio(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_g_audio(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_g_audio(struct sn9c102_device *cam, void __user *arg)
{
struct v4l2_audio audio;
@@ -3106,7 +3110,7 @@ sn9c102_vidioc_g_audio(struct sn9c102_device* cam, void __user * arg)
static int
-sn9c102_vidioc_s_audio(struct sn9c102_device* cam, void __user * arg)
+sn9c102_vidioc_s_audio(struct sn9c102_device *cam, void __user *arg)
{
struct v4l2_audio audio;
@@ -3266,10 +3270,10 @@ static const struct v4l2_file_operations sn9c102_fops = {
/* It exists a single interface only. We do not need to validate anything. */
static int
-sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
+sn9c102_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
- struct sn9c102_device* cam;
+ struct sn9c102_device *cam;
static unsigned int dev_nr;
unsigned int i;
int err = 0, r;
@@ -3419,9 +3423,9 @@ fail:
}
-static void sn9c102_usb_disconnect(struct usb_interface* intf)
+static void sn9c102_usb_disconnect(struct usb_interface *intf)
{
- struct sn9c102_device* cam;
+ struct sn9c102_device *cam;
down_write(&sn9c102_dev_lock);
diff --git a/drivers/staging/media/sn9c102/sn9c102_devtable.h b/drivers/staging/media/sn9c102/sn9c102_devtable.h
index 4ba569258498..b187a8a304eb 100644
--- a/drivers/staging/media/sn9c102/sn9c102_devtable.h
+++ b/drivers/staging/media/sn9c102/sn9c102_devtable.h
@@ -129,17 +129,17 @@ static const struct usb_device_id sn9c102_id_table[] = {
initialization of the SN9C1XX chip.
Functions must return 0 on success, the appropriate error otherwise.
*/
-extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
-extern int sn9c102_probe_hv7131r(struct sn9c102_device* cam);
-extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
-extern int sn9c102_probe_mi0360(struct sn9c102_device* cam);
+extern int sn9c102_probe_hv7131d(struct sn9c102_device *cam);
+extern int sn9c102_probe_hv7131r(struct sn9c102_device *cam);
+extern int sn9c102_probe_mi0343(struct sn9c102_device *cam);
+extern int sn9c102_probe_mi0360(struct sn9c102_device *cam);
extern int sn9c102_probe_mt9v111(struct sn9c102_device *cam);
-extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
-extern int sn9c102_probe_ov7660(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
-extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
-extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
-extern int sn9c102_probe_tas5110d(struct sn9c102_device* cam);
-extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
+extern int sn9c102_probe_ov7630(struct sn9c102_device *cam);
+extern int sn9c102_probe_ov7660(struct sn9c102_device *cam);
+extern int sn9c102_probe_pas106b(struct sn9c102_device *cam);
+extern int sn9c102_probe_pas202bcb(struct sn9c102_device *cam);
+extern int sn9c102_probe_tas5110c1b(struct sn9c102_device *cam);
+extern int sn9c102_probe_tas5110d(struct sn9c102_device *cam);
+extern int sn9c102_probe_tas5130d1b(struct sn9c102_device *cam);
#endif /* _SN9C102_DEVTABLE_H_ */
diff --git a/drivers/staging/media/sn9c102/sn9c102_hv7131d.c b/drivers/staging/media/sn9c102/sn9c102_hv7131d.c
index 468072176527..f1d94f0190c6 100644
--- a/drivers/staging/media/sn9c102/sn9c102_hv7131d.c
+++ b/drivers/staging/media/sn9c102/sn9c102_hv7131d.c
@@ -23,7 +23,7 @@
#include "sn9c102_devtable.h"
-static int hv7131d_init(struct sn9c102_device* cam)
+static int hv7131d_init(struct sn9c102_device *cam)
{
int err;
@@ -39,8 +39,8 @@ static int hv7131d_init(struct sn9c102_device* cam)
}
-static int hv7131d_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
+static int hv7131d_get_ctrl(struct sn9c102_device *cam,
+ struct v4l2_control *ctrl)
{
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
@@ -88,8 +88,8 @@ static int hv7131d_get_ctrl(struct sn9c102_device* cam,
}
-static int hv7131d_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
+static int hv7131d_set_ctrl(struct sn9c102_device *cam,
+ const struct v4l2_control *ctrl)
{
int err = 0;
@@ -121,10 +121,10 @@ static int hv7131d_set_ctrl(struct sn9c102_device* cam,
}
-static int hv7131d_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
+static int hv7131d_set_crop(struct sn9c102_device *cam,
+ const struct v4l2_rect *rect)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 2,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
@@ -136,8 +136,8 @@ static int hv7131d_set_crop(struct sn9c102_device* cam,
}
-static int hv7131d_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
+static int hv7131d_set_pix_format(struct sn9c102_device *cam,
+ const struct v4l2_pix_format *pix)
{
int err = 0;
@@ -248,7 +248,7 @@ static const struct sn9c102_sensor hv7131d = {
};
-int sn9c102_probe_hv7131d(struct sn9c102_device* cam)
+int sn9c102_probe_hv7131d(struct sn9c102_device *cam)
{
int r0 = 0, r1 = 0, err;
diff --git a/drivers/staging/media/sn9c102/sn9c102_hv7131r.c b/drivers/staging/media/sn9c102/sn9c102_hv7131r.c
index 26a91115b831..51b24e000e88 100644
--- a/drivers/staging/media/sn9c102/sn9c102_hv7131r.c
+++ b/drivers/staging/media/sn9c102/sn9c102_hv7131r.c
@@ -23,7 +23,7 @@
#include "sn9c102_devtable.h"
-static int hv7131r_init(struct sn9c102_device* cam)
+static int hv7131r_init(struct sn9c102_device *cam)
{
int err = 0;
@@ -137,8 +137,8 @@ static int hv7131r_init(struct sn9c102_device* cam)
}
-static int hv7131r_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
+static int hv7131r_get_ctrl(struct sn9c102_device *cam,
+ struct v4l2_control *ctrl)
{
switch (ctrl->id) {
case V4L2_CID_GAIN:
@@ -176,8 +176,8 @@ static int hv7131r_get_ctrl(struct sn9c102_device* cam,
}
-static int hv7131r_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
+static int hv7131r_set_ctrl(struct sn9c102_device *cam,
+ const struct v4l2_control *ctrl)
{
int err = 0;
@@ -197,6 +197,7 @@ static int hv7131r_set_ctrl(struct sn9c102_device* cam,
case V4L2_CID_BLACK_LEVEL:
{
int r = sn9c102_i2c_read(cam, 0x01);
+
if (r < 0)
return -EIO;
err += sn9c102_i2c_write(cam, 0x01,
@@ -211,10 +212,10 @@ static int hv7131r_set_ctrl(struct sn9c102_device* cam,
}
-static int hv7131r_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
+static int hv7131r_set_crop(struct sn9c102_device *cam,
+ const struct v4l2_rect *rect)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
@@ -226,8 +227,8 @@ static int hv7131r_set_crop(struct sn9c102_device* cam,
}
-static int hv7131r_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
+static int hv7131r_set_pix_format(struct sn9c102_device *cam,
+ const struct v4l2_pix_format *pix)
{
int err = 0;
@@ -347,7 +348,7 @@ static const struct sn9c102_sensor hv7131r = {
};
-int sn9c102_probe_hv7131r(struct sn9c102_device* cam)
+int sn9c102_probe_hv7131r(struct sn9c102_device *cam)
{
int devid, err;
diff --git a/drivers/staging/media/sn9c102/sn9c102_mi0343.c b/drivers/staging/media/sn9c102/sn9c102_mi0343.c
index 1f5b09bec89c..b20fdb6541d3 100644
--- a/drivers/staging/media/sn9c102/sn9c102_mi0343.c
+++ b/drivers/staging/media/sn9c102/sn9c102_mi0343.c
@@ -23,9 +23,9 @@
#include "sn9c102_devtable.h"
-static int mi0343_init(struct sn9c102_device* cam)
+static int mi0343_init(struct sn9c102_device *cam)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
int err = 0;
err = sn9c102_write_const_regs(cam, {0x00, 0x10}, {0x00, 0x11},
@@ -52,10 +52,10 @@ static int mi0343_init(struct sn9c102_device* cam)
}
-static int mi0343_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
+static int mi0343_get_ctrl(struct sn9c102_device *cam,
+ struct v4l2_control *ctrl)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
u8 data[2];
switch (ctrl->id) {
@@ -119,10 +119,10 @@ static int mi0343_get_ctrl(struct sn9c102_device* cam,
}
-static int mi0343_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
+static int mi0343_set_ctrl(struct sn9c102_device *cam,
+ const struct v4l2_control *ctrl)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
u16 reg = 0;
int err = 0;
@@ -189,10 +189,10 @@ static int mi0343_set_ctrl(struct sn9c102_device* cam,
}
-static int mi0343_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
+static int mi0343_set_crop(struct sn9c102_device *cam,
+ const struct v4l2_rect *rect)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 0,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 2;
@@ -204,10 +204,10 @@ static int mi0343_set_crop(struct sn9c102_device* cam,
}
-static int mi0343_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
+static int mi0343_set_pix_format(struct sn9c102_device *cam,
+ const struct v4l2_pix_format *pix)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
int err = 0;
if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X) {
@@ -331,7 +331,7 @@ static const struct sn9c102_sensor mi0343 = {
};
-int sn9c102_probe_mi0343(struct sn9c102_device* cam)
+int sn9c102_probe_mi0343(struct sn9c102_device *cam)
{
u8 data[2];
diff --git a/drivers/staging/media/sn9c102/sn9c102_mi0360.c b/drivers/staging/media/sn9c102/sn9c102_mi0360.c
index d973fc1973d9..5f21d1b43e32 100644
--- a/drivers/staging/media/sn9c102/sn9c102_mi0360.c
+++ b/drivers/staging/media/sn9c102/sn9c102_mi0360.c
@@ -23,9 +23,9 @@
#include "sn9c102_devtable.h"
-static int mi0360_init(struct sn9c102_device* cam)
+static int mi0360_init(struct sn9c102_device *cam)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
int err = 0;
switch (sn9c102_get_bridge(cam)) {
@@ -147,10 +147,10 @@ static int mi0360_init(struct sn9c102_device* cam)
}
-static int mi0360_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
+static int mi0360_get_ctrl(struct sn9c102_device *cam,
+ struct v4l2_control *ctrl)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
u8 data[2];
switch (ctrl->id) {
@@ -204,10 +204,10 @@ static int mi0360_get_ctrl(struct sn9c102_device* cam,
}
-static int mi0360_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
+static int mi0360_set_ctrl(struct sn9c102_device *cam,
+ const struct v4l2_control *ctrl)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
int err = 0;
switch (ctrl->id) {
@@ -259,10 +259,10 @@ static int mi0360_set_ctrl(struct sn9c102_device* cam,
}
-static int mi0360_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
+static int mi0360_set_crop(struct sn9c102_device *cam,
+ const struct v4l2_rect *rect)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
@@ -285,10 +285,10 @@ static int mi0360_set_crop(struct sn9c102_device* cam,
}
-static int mi0360_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
+static int mi0360_set_pix_format(struct sn9c102_device *cam,
+ const struct v4l2_pix_format *pix)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
int err = 0;
if (pix->pixelformat == V4L2_PIX_FMT_SBGGR8) {
@@ -418,7 +418,7 @@ static const struct sn9c102_sensor mi0360 = {
};
-int sn9c102_probe_mi0360(struct sn9c102_device* cam)
+int sn9c102_probe_mi0360(struct sn9c102_device *cam)
{
u8 data[2];
diff --git a/drivers/staging/media/sn9c102/sn9c102_ov7630.c b/drivers/staging/media/sn9c102/sn9c102_ov7630.c
index d3a1bd8d5648..9ec304dc4705 100644
--- a/drivers/staging/media/sn9c102/sn9c102_ov7630.c
+++ b/drivers/staging/media/sn9c102/sn9c102_ov7630.c
@@ -23,7 +23,7 @@
#include "sn9c102_devtable.h"
-static int ov7630_init(struct sn9c102_device* cam)
+static int ov7630_init(struct sn9c102_device *cam)
{
int err = 0;
@@ -252,8 +252,8 @@ static int ov7630_init(struct sn9c102_device* cam)
}
-static int ov7630_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
+static int ov7630_get_ctrl(struct sn9c102_device *cam,
+ struct v4l2_control *ctrl)
{
enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
int err = 0;
@@ -330,8 +330,8 @@ static int ov7630_get_ctrl(struct sn9c102_device* cam,
}
-static int ov7630_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
+static int ov7630_set_ctrl(struct sn9c102_device *cam,
+ const struct v4l2_control *ctrl)
{
enum sn9c102_bridge bridge = sn9c102_get_bridge(cam);
int err = 0;
@@ -385,10 +385,10 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
}
-static int ov7630_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
+static int ov7630_set_crop(struct sn9c102_device *cam,
+ const struct v4l2_rect *rect)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = 0, v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
@@ -413,8 +413,8 @@ static int ov7630_set_crop(struct sn9c102_device* cam,
}
-static int ov7630_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
+static int ov7630_set_pix_format(struct sn9c102_device *cam,
+ const struct v4l2_pix_format *pix)
{
int err = 0;
@@ -594,7 +594,7 @@ static const struct sn9c102_sensor ov7630 = {
};
-int sn9c102_probe_ov7630(struct sn9c102_device* cam)
+int sn9c102_probe_ov7630(struct sn9c102_device *cam)
{
int pid, ver, err = 0;
diff --git a/drivers/staging/media/sn9c102/sn9c102_ov7660.c b/drivers/staging/media/sn9c102/sn9c102_ov7660.c
index 530157a234e6..ac07805d122e 100644
--- a/drivers/staging/media/sn9c102/sn9c102_ov7660.c
+++ b/drivers/staging/media/sn9c102/sn9c102_ov7660.c
@@ -23,7 +23,7 @@
#include "sn9c102_devtable.h"
-static int ov7660_init(struct sn9c102_device* cam)
+static int ov7660_init(struct sn9c102_device *cam)
{
int err = 0;
@@ -271,8 +271,8 @@ static int ov7660_init(struct sn9c102_device* cam)
}
-static int ov7660_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
+static int ov7660_get_ctrl(struct sn9c102_device *cam,
+ struct v4l2_control *ctrl)
{
int err = 0;
@@ -332,8 +332,8 @@ static int ov7660_get_ctrl(struct sn9c102_device* cam,
}
-static int ov7660_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
+static int ov7660_set_ctrl(struct sn9c102_device *cam,
+ const struct v4l2_control *ctrl)
{
int err = 0;
@@ -371,10 +371,10 @@ static int ov7660_set_ctrl(struct sn9c102_device* cam,
}
-static int ov7660_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
+static int ov7660_set_crop(struct sn9c102_device *cam,
+ const struct v4l2_rect *rect)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 1,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
@@ -386,8 +386,8 @@ static int ov7660_set_crop(struct sn9c102_device* cam,
}
-static int ov7660_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
+static int ov7660_set_pix_format(struct sn9c102_device *cam,
+ const struct v4l2_pix_format *pix)
{
int r0, err = 0;
@@ -525,7 +525,7 @@ static const struct sn9c102_sensor ov7660 = {
};
-int sn9c102_probe_ov7660(struct sn9c102_device* cam)
+int sn9c102_probe_ov7660(struct sn9c102_device *cam)
{
int pid, ver, err;
diff --git a/drivers/staging/media/sn9c102/sn9c102_pas106b.c b/drivers/staging/media/sn9c102/sn9c102_pas106b.c
index 47bd82de80f9..895931ecac48 100644
--- a/drivers/staging/media/sn9c102/sn9c102_pas106b.c
+++ b/drivers/staging/media/sn9c102/sn9c102_pas106b.c
@@ -24,7 +24,7 @@
#include "sn9c102_devtable.h"
-static int pas106b_init(struct sn9c102_device* cam)
+static int pas106b_init(struct sn9c102_device *cam)
{
int err = 0;
@@ -48,8 +48,8 @@ static int pas106b_init(struct sn9c102_device* cam)
}
-static int pas106b_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
+static int pas106b_get_ctrl(struct sn9c102_device *cam,
+ struct v4l2_control *ctrl)
{
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
@@ -103,8 +103,8 @@ static int pas106b_get_ctrl(struct sn9c102_device* cam,
}
-static int pas106b_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
+static int pas106b_set_ctrl(struct sn9c102_device *cam,
+ const struct v4l2_control *ctrl)
{
int err = 0;
@@ -141,10 +141,10 @@ static int pas106b_set_ctrl(struct sn9c102_device* cam,
}
-static int pas106b_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
+static int pas106b_set_crop(struct sn9c102_device *cam,
+ const struct v4l2_rect *rect)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 4,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
@@ -156,8 +156,8 @@ static int pas106b_set_crop(struct sn9c102_device* cam,
}
-static int pas106b_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
+static int pas106b_set_pix_format(struct sn9c102_device *cam,
+ const struct v4l2_pix_format *pix)
{
int err = 0;
@@ -278,7 +278,7 @@ static const struct sn9c102_sensor pas106b = {
};
-int sn9c102_probe_pas106b(struct sn9c102_device* cam)
+int sn9c102_probe_pas106b(struct sn9c102_device *cam)
{
int r0 = 0, r1 = 0;
unsigned int pid = 0;
diff --git a/drivers/staging/media/sn9c102/sn9c102_pas202bcb.c b/drivers/staging/media/sn9c102/sn9c102_pas202bcb.c
index cbfacc2dad84..f9e31ae2ad9f 100644
--- a/drivers/staging/media/sn9c102/sn9c102_pas202bcb.c
+++ b/drivers/staging/media/sn9c102/sn9c102_pas202bcb.c
@@ -28,7 +28,7 @@
#include "sn9c102_devtable.h"
-static int pas202bcb_init(struct sn9c102_device* cam)
+static int pas202bcb_init(struct sn9c102_device *cam)
{
int err = 0;
@@ -78,8 +78,8 @@ static int pas202bcb_init(struct sn9c102_device* cam)
}
-static int pas202bcb_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
+static int pas202bcb_get_ctrl(struct sn9c102_device *cam,
+ struct v4l2_control *ctrl)
{
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
@@ -126,8 +126,8 @@ static int pas202bcb_get_ctrl(struct sn9c102_device* cam,
}
-static int pas202bcb_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
+static int pas202bcb_set_pix_format(struct sn9c102_device *cam,
+ const struct v4l2_pix_format *pix)
{
int err = 0;
@@ -140,8 +140,8 @@ static int pas202bcb_set_pix_format(struct sn9c102_device* cam,
}
-static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
+static int pas202bcb_set_ctrl(struct sn9c102_device *cam,
+ const struct v4l2_control *ctrl)
{
int err = 0;
@@ -174,10 +174,10 @@ static int pas202bcb_set_ctrl(struct sn9c102_device* cam,
}
-static int pas202bcb_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
+static int pas202bcb_set_crop(struct sn9c102_device *cam,
+ const struct v4l2_rect *rect)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = 0,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
@@ -299,7 +299,7 @@ static const struct sn9c102_sensor pas202bcb = {
};
-int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
+int sn9c102_probe_pas202bcb(struct sn9c102_device *cam)
{
int r0 = 0, r1 = 0, err = 0;
unsigned int pid = 0;
diff --git a/drivers/staging/media/sn9c102/sn9c102_sensor.h b/drivers/staging/media/sn9c102/sn9c102_sensor.h
index 3679970dba2c..9f59c815d48b 100644
--- a/drivers/staging/media/sn9c102/sn9c102_sensor.h
+++ b/drivers/staging/media/sn9c102/sn9c102_sensor.h
@@ -62,19 +62,19 @@ enum sn9c102_bridge {
};
/* Return the bridge name */
-enum sn9c102_bridge sn9c102_get_bridge(struct sn9c102_device* cam);
+enum sn9c102_bridge sn9c102_get_bridge(struct sn9c102_device *cam);
/* Return a pointer the sensor struct attached to the camera */
-struct sn9c102_sensor* sn9c102_get_sensor(struct sn9c102_device* cam);
+struct sn9c102_sensor *sn9c102_get_sensor(struct sn9c102_device *cam);
/* Identify a device */
extern struct sn9c102_device*
-sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
+sn9c102_match_id(struct sn9c102_device *cam, const struct usb_device_id *id);
/* Attach a probed sensor to the camera. */
extern void
-sn9c102_attach_sensor(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor);
+sn9c102_attach_sensor(struct sn9c102_device *cam,
+ const struct sn9c102_sensor *sensor);
/*
Read/write routines: they always return -1 on error, 0 or the read value
@@ -99,12 +99,12 @@ extern int sn9c102_i2c_try_read(struct sn9c102_device*,
version returns 0 on success, while the read version returns the first read
byte.
*/
-extern int sn9c102_i2c_try_raw_write(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor, u8 n,
+extern int sn9c102_i2c_try_raw_write(struct sn9c102_device *cam,
+ const struct sn9c102_sensor *sensor, u8 n,
u8 data0, u8 data1, u8 data2, u8 data3,
u8 data4, u8 data5);
-extern int sn9c102_i2c_try_raw_read(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor,
+extern int sn9c102_i2c_try_raw_read(struct sn9c102_device *cam,
+ const struct sn9c102_sensor *sensor,
u8 data0, u8 data1, u8 n, u8 buffer[]);
/* To be used after the sensor struct has been attached to the camera struct */
@@ -174,7 +174,7 @@ struct sn9c102_sensor {
they must return 0 on success, the proper error otherwise.
*/
- int (*init)(struct sn9c102_device* cam);
+ int (*init)(struct sn9c102_device *cam);
/*
This function will be called after the sensor has been attached.
It should be used to initialize the sensor only, but may also
@@ -195,9 +195,9 @@ struct sn9c102_sensor {
V4L2 API. Menu type controls are not handled by this interface.
*/
- int (*get_ctrl)(struct sn9c102_device* cam, struct v4l2_control* ctrl);
- int (*set_ctrl)(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl);
+ int (*get_ctrl)(struct sn9c102_device *cam, struct v4l2_control *ctrl);
+ int (*set_ctrl)(struct sn9c102_device *cam,
+ const struct v4l2_control *ctrl);
/*
You must implement at least the set_ctrl method if you have defined
the list above. The returned value must follow the V4L2
@@ -240,8 +240,8 @@ struct sn9c102_sensor {
will be ignored.
*/
- int (*set_crop)(struct sn9c102_device* cam,
- const struct v4l2_rect* rect);
+ int (*set_crop)(struct sn9c102_device *cam,
+ const struct v4l2_rect *rect);
/*
To be called on VIDIOC_C_SETCROP. The core module always calls a
default routine which configures the appropriate SN9C1XX regs (also
@@ -276,8 +276,8 @@ struct sn9c102_sensor {
matches the RGB bayer sequence (i.e. BGBGBG...GRGRGR).
*/
- int (*set_pix_format)(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix);
+ int (*set_pix_format)(struct sn9c102_device *cam,
+ const struct v4l2_pix_format *pix);
/*
To be called on VIDIOC_S_FMT, when switching from the SBGGR8 to
SN9C10X pixel format or viceversa. On error return the corresponding
diff --git a/drivers/staging/media/sn9c102/sn9c102_tas5110c1b.c b/drivers/staging/media/sn9c102/sn9c102_tas5110c1b.c
index 04cdfdde8564..6a00b626d347 100644
--- a/drivers/staging/media/sn9c102/sn9c102_tas5110c1b.c
+++ b/drivers/staging/media/sn9c102/sn9c102_tas5110c1b.c
@@ -23,7 +23,7 @@
#include "sn9c102_devtable.h"
-static int tas5110c1b_init(struct sn9c102_device* cam)
+static int tas5110c1b_init(struct sn9c102_device *cam)
{
int err = 0;
@@ -38,8 +38,8 @@ static int tas5110c1b_init(struct sn9c102_device* cam)
}
-static int tas5110c1b_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
+static int tas5110c1b_set_ctrl(struct sn9c102_device *cam,
+ const struct v4l2_control *ctrl)
{
int err = 0;
@@ -55,10 +55,10 @@ static int tas5110c1b_set_ctrl(struct sn9c102_device* cam,
}
-static int tas5110c1b_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
+static int tas5110c1b_set_crop(struct sn9c102_device *cam,
+ const struct v4l2_rect *rect)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
@@ -75,8 +75,8 @@ static int tas5110c1b_set_crop(struct sn9c102_device* cam,
}
-static int tas5110c1b_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
+static int tas5110c1b_set_pix_format(struct sn9c102_device *cam,
+ const struct v4l2_pix_format *pix)
{
int err = 0;
@@ -135,7 +135,7 @@ static const struct sn9c102_sensor tas5110c1b = {
};
-int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
+int sn9c102_probe_tas5110c1b(struct sn9c102_device *cam)
{
const struct usb_device_id tas5110c1b_id_table[] = {
{ USB_DEVICE(0x0c45, 0x6001), },
diff --git a/drivers/staging/media/sn9c102/sn9c102_tas5110d.c b/drivers/staging/media/sn9c102/sn9c102_tas5110d.c
index 9372e6f9fcff..eefbf8670c3e 100644
--- a/drivers/staging/media/sn9c102/sn9c102_tas5110d.c
+++ b/drivers/staging/media/sn9c102/sn9c102_tas5110d.c
@@ -23,7 +23,7 @@
#include "sn9c102_devtable.h"
-static int tas5110d_init(struct sn9c102_device* cam)
+static int tas5110d_init(struct sn9c102_device *cam)
{
int err;
@@ -37,10 +37,10 @@ static int tas5110d_init(struct sn9c102_device* cam)
}
-static int tas5110d_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
+static int tas5110d_set_crop(struct sn9c102_device *cam,
+ const struct v4l2_rect *rect)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 69,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 9;
@@ -55,8 +55,8 @@ static int tas5110d_set_crop(struct sn9c102_device* cam,
}
-static int tas5110d_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
+static int tas5110d_set_pix_format(struct sn9c102_device *cam,
+ const struct v4l2_pix_format *pix)
{
int err = 0;
@@ -103,7 +103,7 @@ static const struct sn9c102_sensor tas5110d = {
};
-int sn9c102_probe_tas5110d(struct sn9c102_device* cam)
+int sn9c102_probe_tas5110d(struct sn9c102_device *cam)
{
const struct usb_device_id tas5110d_id_table[] = {
{ USB_DEVICE(0x0c45, 0x6007), },
diff --git a/drivers/staging/media/sn9c102/sn9c102_tas5130d1b.c b/drivers/staging/media/sn9c102/sn9c102_tas5130d1b.c
index a30bbc4389f5..725de857de45 100644
--- a/drivers/staging/media/sn9c102/sn9c102_tas5130d1b.c
+++ b/drivers/staging/media/sn9c102/sn9c102_tas5130d1b.c
@@ -23,7 +23,7 @@
#include "sn9c102_devtable.h"
-static int tas5130d1b_init(struct sn9c102_device* cam)
+static int tas5130d1b_init(struct sn9c102_device *cam)
{
int err;
@@ -36,8 +36,8 @@ static int tas5130d1b_init(struct sn9c102_device* cam)
}
-static int tas5130d1b_set_ctrl(struct sn9c102_device* cam,
- const struct v4l2_control* ctrl)
+static int tas5130d1b_set_ctrl(struct sn9c102_device *cam,
+ const struct v4l2_control *ctrl)
{
int err = 0;
@@ -56,10 +56,10 @@ static int tas5130d1b_set_ctrl(struct sn9c102_device* cam,
}
-static int tas5130d1b_set_crop(struct sn9c102_device* cam,
- const struct v4l2_rect* rect)
+static int tas5130d1b_set_crop(struct sn9c102_device *cam,
+ const struct v4l2_rect *rect)
{
- struct sn9c102_sensor* s = sn9c102_get_sensor(cam);
+ struct sn9c102_sensor *s = sn9c102_get_sensor(cam);
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 104,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 12;
int err = 0;
@@ -76,8 +76,8 @@ static int tas5130d1b_set_crop(struct sn9c102_device* cam,
}
-static int tas5130d1b_set_pix_format(struct sn9c102_device* cam,
- const struct v4l2_pix_format* pix)
+static int tas5130d1b_set_pix_format(struct sn9c102_device *cam,
+ const struct v4l2_pix_format *pix)
{
int err = 0;
@@ -146,7 +146,7 @@ static const struct sn9c102_sensor tas5130d1b = {
};
-int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
+int sn9c102_probe_tas5130d1b(struct sn9c102_device *cam)
{
const struct usb_device_id tas5130d1b_id_table[] = {
{ USB_DEVICE(0x0c45, 0x6024), },
diff --git a/drivers/staging/media/solo6x10/Kconfig b/drivers/staging/media/solo6x10/Kconfig
index 9a4296c2e3ab..6a1906fa1117 100644
--- a/drivers/staging/media/solo6x10/Kconfig
+++ b/drivers/staging/media/solo6x10/Kconfig
@@ -1,5 +1,5 @@
config SOLO6X10
- tristate "Softlogic 6x10 MPEG codec cards"
+ tristate "Bluecherry / Softlogic 6x10 capture cards (MPEG-4/H.264)"
depends on PCI && VIDEO_DEV && SND && I2C
select FONT_SUPPORT
select FONT_8x16
@@ -8,5 +8,11 @@ config SOLO6X10
select SND_PCM
select FONT_8x16
---help---
- This driver supports the Softlogic based MPEG-4 and h.264 codec
- cards.
+ This driver supports the Bluecherry H.264 and MPEG-4 hardware
+ compression capture cards and other Softlogic-based ones.
+
+ Following cards have been tested:
+ * Bluecherry BC-H16480A (PCIe, 16 port, H.264)
+ * Bluecherry BC-H04120A (PCIe, 4 port, H.264)
+ * Bluecherry BC-H04120A-MPCI (Mini-PCI, 4 port, H.264)
+ * Bluecherry BC-04120A (PCIe, 4 port, MPEG-4)
diff --git a/drivers/staging/media/solo6x10/solo6x10-enc.c b/drivers/staging/media/solo6x10/solo6x10-enc.c
index 94d5735abf85..2db53b68c62f 100644
--- a/drivers/staging/media/solo6x10/solo6x10-enc.c
+++ b/drivers/staging/media/solo6x10/solo6x10-enc.c
@@ -134,51 +134,48 @@ static void solo_capture_config(struct solo_dev *solo_dev)
kfree(buf);
}
+#define SOLO_OSD_WRITE_SIZE (16 * OSD_TEXT_MAX)
+
/* Should be called with enable_lock held */
int solo_osd_print(struct solo_enc_dev *solo_enc)
{
struct solo_dev *solo_dev = solo_enc->solo_dev;
unsigned char *str = solo_enc->osd_text;
u8 *buf = solo_enc->osd_buf;
- u32 reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH);
+ u32 reg;
const struct font_desc *vga = find_font("VGA8x16");
const unsigned char *vga_data;
- int len;
int i, j;
if (WARN_ON_ONCE(!vga))
return -ENODEV;
- len = strlen(str);
-
- if (len == 0) {
+ reg = solo_reg_read(solo_dev, SOLO_VE_OSD_CH);
+ if (!*str) {
/* Disable OSD on this channel */
reg &= ~(1 << solo_enc->ch);
- solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
- return 0;
+ goto out;
}
- memset(buf, 0, SOLO_EOSD_EXT_SIZE_MAX);
+ memset(buf, 0, SOLO_OSD_WRITE_SIZE);
vga_data = (const unsigned char *)vga->data;
- for (i = 0; i < len; i++) {
- unsigned char c = str[i];
-
+ for (i = 0; *str; i++, str++) {
for (j = 0; j < 16; j++) {
- buf[(j * 2) + (i % 2) + (i / 2 * 32)] =
- bitrev8(vga_data[(c * 16) + j]);
+ buf[(j << 1) | (i & 1) | ((i & ~1) << 4)] =
+ bitrev8(vga_data[(*str << 4) | j]);
}
}
solo_p2m_dma(solo_dev, 1, buf,
- SOLO_EOSD_EXT_ADDR +
- (solo_enc->ch * SOLO_EOSD_EXT_SIZE(solo_dev)),
- SOLO_EOSD_EXT_SIZE(solo_dev), 0, 0);
+ SOLO_EOSD_EXT_ADDR_CHAN(solo_dev, solo_enc->ch),
+ SOLO_OSD_WRITE_SIZE, 0, 0);
/* Enable OSD on this channel */
reg |= (1 << solo_enc->ch);
- solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
+out:
+ solo_reg_write(solo_dev, SOLO_VE_OSD_CH, reg);
return 0;
}
diff --git a/drivers/staging/media/solo6x10/solo6x10-offsets.h b/drivers/staging/media/solo6x10/solo6x10-offsets.h
index f005dca501f1..13eeb4470dcf 100644
--- a/drivers/staging/media/solo6x10/solo6x10-offsets.h
+++ b/drivers/staging/media/solo6x10/solo6x10-offsets.h
@@ -35,6 +35,8 @@
#define SOLO_EOSD_EXT_SIZE_MAX 0x20000
#define SOLO_EOSD_EXT_AREA(__solo) \
(SOLO_EOSD_EXT_SIZE(__solo) * 32)
+#define SOLO_EOSD_EXT_ADDR_CHAN(__solo, ch) \
+ (SOLO_EOSD_EXT_ADDR + SOLO_EOSD_EXT_SIZE(__solo) * (ch))
#define SOLO_MOTION_EXT_ADDR(__solo) \
(SOLO_EOSD_EXT_ADDR + SOLO_EOSD_EXT_AREA(__solo))
diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
index 2cbe088f1697..b8ff113c20f4 100644
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
@@ -745,14 +745,13 @@ static int solo_enc_start_streaming(struct vb2_queue *q, unsigned int count)
return solo_ring_start(solo_enc->solo_dev);
}
-static int solo_enc_stop_streaming(struct vb2_queue *q)
+static void solo_enc_stop_streaming(struct vb2_queue *q)
{
struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
solo_enc_off(solo_enc);
INIT_LIST_HEAD(&solo_enc->vidq_active);
solo_ring_stop(solo_enc->solo_dev);
- return 0;
}
static struct vb2_ops solo_enc_video_qops = {
diff --git a/drivers/staging/media/solo6x10/solo6x10-v4l2.c b/drivers/staging/media/solo6x10/solo6x10-v4l2.c
index 1815f765d033..5d0100eb38e6 100644
--- a/drivers/staging/media/solo6x10/solo6x10-v4l2.c
+++ b/drivers/staging/media/solo6x10/solo6x10-v4l2.c
@@ -336,13 +336,12 @@ static int solo_start_streaming(struct vb2_queue *q, unsigned int count)
return solo_start_thread(solo_dev);
}
-static int solo_stop_streaming(struct vb2_queue *q)
+static void solo_stop_streaming(struct vb2_queue *q)
{
struct solo_dev *solo_dev = vb2_get_drv_priv(q);
solo_stop_thread(solo_dev);
INIT_LIST_HEAD(&solo_dev->vidq_active);
- return 0;
}
static void solo_buf_queue(struct vb2_buffer *vb)
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c
index 4246262c4bd2..84a75f89bf74 100644
--- a/drivers/thermal/cpu_cooling.c
+++ b/drivers/thermal/cpu_cooling.c
@@ -144,11 +144,11 @@ static int get_property(unsigned int cpu, unsigned long input,
unsigned int *output,
enum cpufreq_cooling_property property)
{
- int i, j;
+ int i;
unsigned long max_level = 0, level = 0;
unsigned int freq = CPUFREQ_ENTRY_INVALID;
int descend = -1;
- struct cpufreq_frequency_table *table =
+ struct cpufreq_frequency_table *pos, *table =
cpufreq_frequency_get_table(cpu);
if (!output)
@@ -157,20 +157,16 @@ static int get_property(unsigned int cpu, unsigned long input,
if (!table)
return -EINVAL;
- for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
- /* ignore invalid entries */
- if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
- continue;
-
+ cpufreq_for_each_valid_entry(pos, table) {
/* ignore duplicate entry */
- if (freq == table[i].frequency)
+ if (freq == pos->frequency)
continue;
/* get the frequency order */
if (freq != CPUFREQ_ENTRY_INVALID && descend == -1)
- descend = !!(freq > table[i].frequency);
+ descend = freq > pos->frequency;
- freq = table[i].frequency;
+ freq = pos->frequency;
max_level++;
}
@@ -190,29 +186,26 @@ static int get_property(unsigned int cpu, unsigned long input,
if (property == GET_FREQ)
level = descend ? input : (max_level - input);
- for (i = 0, j = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
- /* ignore invalid entry */
- if (table[i].frequency == CPUFREQ_ENTRY_INVALID)
- continue;
-
+ i = 0;
+ cpufreq_for_each_valid_entry(pos, table) {
/* ignore duplicate entry */
- if (freq == table[i].frequency)
+ if (freq == pos->frequency)
continue;
/* now we have a valid frequency entry */
- freq = table[i].frequency;
+ freq = pos->frequency;
if (property == GET_LEVEL && (unsigned int)input == freq) {
/* get level by frequency */
- *output = descend ? j : (max_level - j);
+ *output = descend ? i : (max_level - i);
return 0;
}
- if (property == GET_FREQ && level == j) {
+ if (property == GET_FREQ && level == i) {
/* get frequency by level */
*output = freq;
return 0;
}
- j++;
+ i++;
}
return -EINVAL;
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index ee3d80346780..908a6e3142a2 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2072,6 +2072,7 @@ static int __init pl011_early_console_setup(struct earlycon_device *device,
return 0;
}
EARLYCON_DECLARE(pl011, pl011_early_console_setup);
+OF_EARLYCON_DECLARE(pl011, "arm,pl011", pl011_early_console_setup);
#else
#define AMBA_CONSOLE NULL
diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c
index c92e83088adb..5131b5ee6164 100644
--- a/drivers/tty/serial/earlycon.c
+++ b/drivers/tty/serial/earlycon.c
@@ -15,6 +15,8 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/serial_core.h>
+#include <linux/sizes.h>
+#include <linux/mod_devicetable.h>
#ifdef CONFIG_FIX_EARLYCON_MEM
#include <asm/fixmap.h>
@@ -32,6 +34,9 @@ static struct earlycon_device early_console_dev = {
.con = &early_con,
};
+static const struct of_device_id __earlycon_of_table_sentinel
+ __used __section(__earlycon_of_table_end);
+
static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)
{
void __iomem *base;
@@ -142,3 +147,26 @@ int __init setup_earlycon(char *buf, const char *match,
register_console(early_console_dev.con);
return 0;
}
+
+int __init of_setup_earlycon(unsigned long addr,
+ int (*setup)(struct earlycon_device *, const char *))
+{
+ int err;
+ struct uart_port *port = &early_console_dev.port;
+
+ port->iotype = UPIO_MEM;
+ port->mapbase = addr;
+ port->uartclk = BASE_BAUD * 16;
+ port->membase = earlycon_map(addr, SZ_4K);
+
+ early_console_dev.con->data = &early_console_dev;
+ err = setup(&early_console_dev, NULL);
+ if (err < 0)
+ return err;
+ if (!early_console_dev.con->write)
+ return -ENODEV;
+
+
+ register_console(early_console_dev.con);
+ return 0;
+}
diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index bd2172c2d650..428089009cd5 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -23,6 +23,7 @@
static struct list_head backlight_dev_list;
static struct mutex backlight_dev_list_mutex;
+static struct blocking_notifier_head backlight_notifier;
static const char *const backlight_types[] = {
[BACKLIGHT_RAW] = "raw",
@@ -370,6 +371,9 @@ struct backlight_device *backlight_device_register(const char *name,
list_add(&new_bd->entry, &backlight_dev_list);
mutex_unlock(&backlight_dev_list_mutex);
+ blocking_notifier_call_chain(&backlight_notifier,
+ BACKLIGHT_REGISTERED, new_bd);
+
return new_bd;
}
EXPORT_SYMBOL(backlight_device_register);
@@ -413,6 +417,10 @@ void backlight_device_unregister(struct backlight_device *bd)
pmac_backlight = NULL;
mutex_unlock(&pmac_backlight_mutex);
#endif
+
+ blocking_notifier_call_chain(&backlight_notifier,
+ BACKLIGHT_UNREGISTERED, bd);
+
mutex_lock(&bd->ops_lock);
bd->ops = NULL;
mutex_unlock(&bd->ops_lock);
@@ -438,6 +446,36 @@ static int devm_backlight_device_match(struct device *dev, void *res,
}
/**
+ * backlight_register_notifier - get notified of backlight (un)registration
+ * @nb: notifier block with the notifier to call on backlight (un)registration
+ *
+ * @return 0 on success, otherwise a negative error code
+ *
+ * Register a notifier to get notified when backlight devices get registered
+ * or unregistered.
+ */
+int backlight_register_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_register(&backlight_notifier, nb);
+}
+EXPORT_SYMBOL(backlight_register_notifier);
+
+/**
+ * backlight_unregister_notifier - unregister a backlight notifier
+ * @nb: notifier block to unregister
+ *
+ * @return 0 on success, otherwise a negative error code
+ *
+ * Register a notifier to get notified when backlight devices get registered
+ * or unregistered.
+ */
+int backlight_unregister_notifier(struct notifier_block *nb)
+{
+ return blocking_notifier_chain_unregister(&backlight_notifier, nb);
+}
+EXPORT_SYMBOL(backlight_unregister_notifier);
+
+/**
* devm_backlight_device_register - resource managed backlight_device_register()
* @dev: the device to register
* @name: the name of the device
@@ -544,6 +582,8 @@ static int __init backlight_class_init(void)
backlight_class->pm = &backlight_class_dev_pm_ops;
INIT_LIST_HEAD(&backlight_dev_list);
mutex_init(&backlight_dev_list_mutex);
+ BLOCKING_INIT_NOTIFIER_HEAD(&backlight_notifier);
+
return 0;
}
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index f447734b09b4..57b1d44acbfe 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -748,6 +748,7 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
fbcon_del_cursor_timer(oldinfo);
kfree(ops->cursor_state.mask);
kfree(ops->cursor_data);
+ kfree(ops->cursor_src);
kfree(ops->fontbuffer);
kfree(oldinfo->fbcon_par);
oldinfo->fbcon_par = NULL;
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index e1f47272fdea..59c98bfd5a8a 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -360,6 +360,7 @@ config FB_CYBER2000_DDC
config FB_CYBER2000_I2C
bool "CyberPro 2000/2010/5000 I2C support"
depends on FB_CYBER2000 && I2C && ARCH_NETWINDER
+ depends on I2C=y || FB_CYBER2000=m
select I2C_ALGOBIT
help
Enable support for the I2C video decoder interface on the
@@ -966,6 +967,7 @@ config FB_S1D13XXX
config FB_ATMEL
tristate "AT91/AT32 LCD Controller support"
depends on FB && HAVE_FB_ATMEL
+ select FB_BACKLIGHT
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -1971,6 +1973,7 @@ config FB_W100
config FB_SH_MOBILE_LCDC
tristate "SuperH Mobile LCDC framebuffer support"
depends on FB && (SUPERH || ARCH_SHMOBILE) && HAVE_CLK
+ depends on FB_SH_MOBILE_MERAM || !FB_SH_MOBILE_MERAM
select FB_SYS_FILLRECT
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
@@ -1993,7 +1996,7 @@ config FB_SH_MOBILE_HDMI
config FB_TMIO
tristate "Toshiba Mobile IO FrameBuffer support"
- depends on FB && MFD_CORE
+ depends on FB && (MFD_TMIO || COMPILE_TEST)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -2062,7 +2065,7 @@ config FB_S3C2410_DEBUG
through sysfs
config FB_NUC900
- bool "NUC900 LCD framebuffer support"
+ tristate "NUC900 LCD framebuffer support"
depends on FB && ARCH_W90X900
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
@@ -2169,7 +2172,7 @@ config FB_XILINX
config FB_GOLDFISH
tristate "Goldfish Framebuffer"
- depends on FB && HAS_DMA
+ depends on FB && HAS_DMA && (GOLDFISH || COMPILE_TEST)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
@@ -2295,6 +2298,7 @@ endchoice
config FB_MB862XX_I2C
bool "Support I2C bus on MB862XX GDC"
depends on FB_MB862XX && I2C
+ depends on FB_MB862XX=m || I2C=y
default y
help
Selecting this option adds Coral-P(A)/Lime GDC I2C bus adapter
@@ -2332,6 +2336,7 @@ config FB_MX3
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
+ select BACKLIGHT_CLASS_DEVICE
default y
help
This is a framebuffer device for the i.MX31 LCD Controller. So
diff --git a/drivers/video/fbdev/bf54x-lq043fb.c b/drivers/video/fbdev/bf54x-lq043fb.c
index e2c42ad8515a..adbef542c998 100644
--- a/drivers/video/fbdev/bf54x-lq043fb.c
+++ b/drivers/video/fbdev/bf54x-lq043fb.c
@@ -717,8 +717,6 @@ static int bfin_bf54x_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int bfin_bf54x_suspend(struct platform_device *pdev, pm_message_t state)
{
- struct fb_info *fbinfo = platform_get_drvdata(pdev);
-
bfin_write_EPPI0_CONTROL(bfin_read_EPPI0_CONTROL() & ~EPPI_EN);
disable_dma(CH_EPPI0);
bfin_write_EPPI0_STATUS(0xFFFF);
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index b6d5008f361f..b5e85f6c1c26 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -433,7 +433,7 @@ static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
image->dx += image->width + 8;
}
} else if (rotate == FB_ROTATE_UD) {
- for (x = 0; x < num && image->dx >= 0; x++) {
+ for (x = 0; x < num; x++) {
info->fbops->fb_imageblit(info, image);
image->dx -= image->width + 8;
}
@@ -445,7 +445,7 @@ static void fb_do_show_logo(struct fb_info *info, struct fb_image *image,
image->dy += image->height + 8;
}
} else if (rotate == FB_ROTATE_CCW) {
- for (x = 0; x < num && image->dy >= 0; x++) {
+ for (x = 0; x < num; x++) {
info->fbops->fb_imageblit(info, image);
image->dy -= image->height + 8;
}
@@ -674,6 +674,7 @@ int fb_show_logo(struct fb_info *info, int rotate)
int fb_prepare_logo(struct fb_info *info, int rotate) { return 0; }
int fb_show_logo(struct fb_info *info, int rotate) { return 0; }
#endif /* CONFIG_LOGO */
+EXPORT_SYMBOL(fb_prepare_logo);
EXPORT_SYMBOL(fb_show_logo);
static void *fb_seq_start(struct seq_file *m, loff_t *pos)
@@ -1179,7 +1180,7 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
return -EFAULT;
if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)
return -EINVAL;
- if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX)
+ if (con2fb.framebuffer >= FB_MAX)
return -EINVAL;
if (!registered_fb[con2fb.framebuffer])
request_module("fb%d", con2fb.framebuffer);
diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c
index c204ebe6187e..5b0e313849bd 100644
--- a/drivers/video/fbdev/core/fbmon.c
+++ b/drivers/video/fbdev/core/fbmon.c
@@ -1012,13 +1012,20 @@ void fb_edid_add_monspecs(unsigned char *edid, struct fb_monspecs *specs)
while (pos < edid[2]) {
u8 len = edid[pos] & 0x1f, type = (edid[pos] >> 5) & 7;
pr_debug("Data block %u of %u bytes\n", type, len);
- if (type == 2)
+ if (type == 2) {
for (i = pos; i < pos + len; i++) {
u8 idx = edid[pos + i] & 0x7f;
svd[svd_n++] = idx;
pr_debug("N%sative mode #%d\n",
edid[pos + i] & 0x80 ? "" : "on-n", idx);
}
+ } else if (type == 3 && len >= 3) {
+ /* Check Vendor Specific Data Block. For HDMI,
+ it is always 00-0C-03 for HDMI Licensing, LLC. */
+ if (edid[pos + 1] == 3 && edid[pos + 2] == 0xc &&
+ edid[pos + 3] == 0)
+ specs->misc |= FB_MISC_HDMI;
+ }
pos += len + 1;
}
diff --git a/drivers/video/fbdev/da8xx-fb.c b/drivers/video/fbdev/da8xx-fb.c
index 6b23508ff0a5..a8484f768d04 100644
--- a/drivers/video/fbdev/da8xx-fb.c
+++ b/drivers/video/fbdev/da8xx-fb.c
@@ -242,6 +242,20 @@ static struct fb_videomode known_lcd_panels[] = {
.sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
.flag = 0,
},
+ [3] = {
+ /* Densitron 84-0023-001T */
+ .name = "Densitron_84-0023-001T",
+ .xres = 320,
+ .yres = 240,
+ .pixclock = KHZ2PICOS(6400),
+ .left_margin = 0,
+ .right_margin = 0,
+ .upper_margin = 0,
+ .lower_margin = 0,
+ .hsync_len = 30,
+ .vsync_len = 3,
+ .sync = 0,
+ },
};
static bool da8xx_fb_is_raster_enabled(void)
diff --git a/drivers/video/fbdev/exynos/Kconfig b/drivers/video/fbdev/exynos/Kconfig
index fcf2d48ac6d1..1f16b4678c71 100644
--- a/drivers/video/fbdev/exynos/Kconfig
+++ b/drivers/video/fbdev/exynos/Kconfig
@@ -4,6 +4,7 @@
menuconfig EXYNOS_VIDEO
bool "Exynos Video driver support"
+ depends on ARCH_S5PV210 || ARCH_EXYNOS
help
This enables support for EXYNOS Video device.
@@ -15,7 +16,6 @@ if EXYNOS_VIDEO
config EXYNOS_MIPI_DSI
bool "EXYNOS MIPI DSI driver support."
- depends on ARCH_S5PV210 || ARCH_EXYNOS
select GENERIC_PHY
help
This enables support for MIPI-DSI device.
diff --git a/drivers/video/fbdev/fb-puv3.c b/drivers/video/fbdev/fb-puv3.c
index 6db9ebd042a3..88fa2e70a0bb 100644
--- a/drivers/video/fbdev/fb-puv3.c
+++ b/drivers/video/fbdev/fb-puv3.c
@@ -18,8 +18,10 @@
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/console.h>
+#include <linux/mm.h>
#include <asm/sizes.h>
+#include <asm/pgtable.h>
#include <mach/hardware.h>
/* Platform_data reserved for unifb registers. */
diff --git a/drivers/video/fbdev/gbefb.c b/drivers/video/fbdev/gbefb.c
index 3ec65a878ac8..4aa56ba78f32 100644
--- a/drivers/video/fbdev/gbefb.c
+++ b/drivers/video/fbdev/gbefb.c
@@ -1068,7 +1068,7 @@ static struct fb_ops gbefb_ops = {
static ssize_t gbefb_show_memsize(struct device *dev, struct device_attribute *attr, char *buf)
{
- return snprintf(buf, PAGE_SIZE, "%d\n", gbe_mem_size);
+ return snprintf(buf, PAGE_SIZE, "%u\n", gbe_mem_size);
}
static DEVICE_ATTR(size, S_IRUGO, gbefb_show_memsize, NULL);
diff --git a/drivers/video/fbdev/grvga.c b/drivers/video/fbdev/grvga.c
index c078701f15f6..2db5bb1a33e8 100644
--- a/drivers/video/fbdev/grvga.c
+++ b/drivers/video/fbdev/grvga.c
@@ -514,9 +514,10 @@ free_fb:
static int grvga_remove(struct platform_device *device)
{
struct fb_info *info = dev_get_drvdata(&device->dev);
- struct grvga_par *par = info->par;
+ struct grvga_par *par;
if (info) {
+ par = info->par;
unregister_framebuffer(info);
fb_dealloc_cmap(&info->cmap);
diff --git a/drivers/video/fbdev/matrox/matroxfb_base.h b/drivers/video/fbdev/matrox/matroxfb_base.h
index 556d96ce40bf..89a8a89a5eb2 100644
--- a/drivers/video/fbdev/matrox/matroxfb_base.h
+++ b/drivers/video/fbdev/matrox/matroxfb_base.h
@@ -698,7 +698,7 @@ void matroxfb_unregister_driver(struct matroxfb_driver* drv);
#define mga_fifo(n) do {} while ((mga_inl(M_FIFOSTATUS) & 0xFF) < (n))
-#define WaitTillIdle() do {} while (mga_inl(M_STATUS) & 0x10000)
+#define WaitTillIdle() do { mga_inl(M_STATUS); do {} while (mga_inl(M_STATUS) & 0x10000); } while (0)
/* code speedup */
#ifdef CONFIG_FB_MATROX_MILLENIUM
diff --git a/drivers/video/fbdev/mbx/Makefile b/drivers/video/fbdev/mbx/Makefile
index 16c1165cf9c7..d7ae5a9bb376 100644
--- a/drivers/video/fbdev/mbx/Makefile
+++ b/drivers/video/fbdev/mbx/Makefile
@@ -1,4 +1,3 @@
# Makefile for the 2700G controller driver.
-obj-$(CONFIG_FB_MBX) += mbxfb.o
-obj-$(CONFIG_FB_MBX_DEBUG) += mbxfbdebugfs.o
+obj-y += mbxfb.o
diff --git a/drivers/video/fbdev/mbx/mbxdebugfs.c b/drivers/video/fbdev/mbx/mbxdebugfs.c
index 4449f249b0e7..e3bc00a75296 100644
--- a/drivers/video/fbdev/mbx/mbxdebugfs.c
+++ b/drivers/video/fbdev/mbx/mbxdebugfs.c
@@ -17,7 +17,7 @@ struct mbxfb_debugfs_data {
static int open_file_generic(struct inode *inode, struct file *file)
{
- file->private_data = inode->u.generic_ip;
+ file->private_data = inode->i_private;
return 0;
}
diff --git a/drivers/video/fbdev/mbx/mbxfb.c b/drivers/video/fbdev/mbx/mbxfb.c
index f0a5392f5fd3..2bd52ed8832c 100644
--- a/drivers/video/fbdev/mbx/mbxfb.c
+++ b/drivers/video/fbdev/mbx/mbxfb.c
@@ -877,6 +877,8 @@ static int mbxfb_resume(struct platform_device *dev)
#ifndef CONFIG_FB_MBX_DEBUG
#define mbxfb_debugfs_init(x) do {} while(0)
#define mbxfb_debugfs_remove(x) do {} while(0)
+#else
+#include "mbxdebugfs.c"
#endif
#define res_size(_r) (((_r)->end - (_r)->start) + 1)
diff --git a/drivers/video/fbdev/mmp/Kconfig b/drivers/video/fbdev/mmp/Kconfig
index d4a4ffc24749..f56a7e2e8136 100644
--- a/drivers/video/fbdev/mmp/Kconfig
+++ b/drivers/video/fbdev/mmp/Kconfig
@@ -1,6 +1,6 @@
menuconfig MMP_DISP
tristate "Marvell MMP Display Subsystem support"
- depends on CPU_PXA910 || CPU_MMP2 || CPU_MMP3 || CPU_PXA988
+ depends on CPU_PXA910 || CPU_MMP2
help
Marvell Display Subsystem support.
diff --git a/drivers/video/fbdev/mmp/fb/mmpfb.c b/drivers/video/fbdev/mmp/fb/mmpfb.c
index 7ab31eb76a8c..910fcc6ecece 100644
--- a/drivers/video/fbdev/mmp/fb/mmpfb.c
+++ b/drivers/video/fbdev/mmp/fb/mmpfb.c
@@ -554,8 +554,8 @@ static void fb_info_clear(struct fb_info *info)
static int mmpfb_probe(struct platform_device *pdev)
{
struct mmp_buffer_driver_mach_info *mi;
- struct fb_info *info = 0;
- struct mmpfb_info *fbi = 0;
+ struct fb_info *info;
+ struct mmpfb_info *fbi;
int ret, modes_num;
mi = pdev->dev.platform_data;
@@ -569,10 +569,6 @@ static int mmpfb_probe(struct platform_device *pdev)
if (info == NULL)
return -ENOMEM;
fbi = info->par;
- if (!fbi) {
- ret = -EINVAL;
- goto failed;
- }
/* init fb */
fbi->fb_info = info;
@@ -667,7 +663,6 @@ failed_free_buff:
fbi->fb_start_dma);
failed_destroy_mutex:
mutex_destroy(&fbi->access_ok);
-failed:
dev_err(fbi->dev, "mmp-fb: frame buffer device init failed\n");
framebuffer_release(info);
diff --git a/drivers/video/fbdev/mmp/hw/Kconfig b/drivers/video/fbdev/mmp/hw/Kconfig
index 02f109a20cd0..c735d133895c 100644
--- a/drivers/video/fbdev/mmp/hw/Kconfig
+++ b/drivers/video/fbdev/mmp/hw/Kconfig
@@ -2,12 +2,12 @@ if MMP_DISP
config MMP_DISP_CONTROLLER
bool "mmp display controller hw support"
- depends on CPU_PXA910 || CPU_MMP2 || CPU_MMP3 || CPU_PXA988
+ depends on CPU_PXA910 || CPU_MMP2
default n
help
Marvell MMP display hw controller support
- this controller is used on Marvell PXA910,
- MMP2, MMP3, PXA988 chips
+ this controller is used on Marvell PXA910 and
+ MMP2 chips
config MMP_DISP_SPI
bool "mmp display controller spi port"
diff --git a/drivers/video/fbdev/mmp/hw/mmp_ctrl.h b/drivers/video/fbdev/mmp/hw/mmp_ctrl.h
index 53301cfdb1ae..56fdeab34355 100644
--- a/drivers/video/fbdev/mmp/hw/mmp_ctrl.h
+++ b/drivers/video/fbdev/mmp/hw/mmp_ctrl.h
@@ -167,11 +167,7 @@ struct lcd_regs {
PN2_IOPAD_CONTROL) : LCD_TOP_CTRL)
/* dither configure */
-#ifdef CONFIG_CPU_PXA988
-#define LCD_DITHER_CTRL (0x01EC)
-#else
#define LCD_DITHER_CTRL (0x00A0)
-#endif
#define DITHER_TBL_INDEX_SEL(s) ((s) << 16)
#define DITHER_MODE2(m) ((m) << 12)
@@ -186,15 +182,6 @@ struct lcd_regs {
#define DITHER_EN1 (1)
/* dither table data was fixed by video bpp of input and output*/
-#ifdef CONFIG_CPU_PXA988
-#define DITHER_TB_4X4_INDEX0 (0x6e4ca280)
-#define DITHER_TB_4X4_INDEX1 (0x5d7f91b3)
-#define DITHER_TB_4X8_INDEX0 (0xb391a280)
-#define DITHER_TB_4X8_INDEX1 (0x7f5d6e4c)
-#define DITHER_TB_4X8_INDEX2 (0x80a291b3)
-#define DITHER_TB_4X8_INDEX3 (0x4c6e5d7f)
-#define LCD_DITHER_TBL_DATA (0x01F0)
-#else
#define DITHER_TB_4X4_INDEX0 (0x3b19f7d5)
#define DITHER_TB_4X4_INDEX1 (0x082ac4e6)
#define DITHER_TB_4X8_INDEX0 (0xf7d508e6)
@@ -202,7 +189,6 @@ struct lcd_regs {
#define DITHER_TB_4X8_INDEX2 (0xc4e6d5f7)
#define DITHER_TB_4X8_INDEX3 (0x082a193b)
#define LCD_DITHER_TBL_DATA (0x00A4)
-#endif
/* Video Frame 0&1 start address registers */
#define LCD_SPU_DMA_START_ADDR_Y0 0x00C0
@@ -933,16 +919,9 @@ struct lcd_regs {
#define LCD_PN2_SQULN2_CTRL (0x02F0)
#define ALL_LAYER_ALPHA_SEL (0x02F4)
-/* pxa988 has different MASTER_CTRL from MMP3/MMP2 */
-#ifdef CONFIG_CPU_PXA988
-#define TIMING_MASTER_CONTROL (0x01F4)
-#define MASTER_ENH(id) (1 << ((id) + 5))
-#define MASTER_ENV(id) (1 << ((id) + 6))
-#else
#define TIMING_MASTER_CONTROL (0x02F8)
#define MASTER_ENH(id) (1 << (id))
#define MASTER_ENV(id) (1 << ((id) + 4))
-#endif
#define DSI_START_SEL_SHIFT(id) (((id) << 1) + 8)
#define timing_master_config(path, dsi_id, lcd_id) \
@@ -1312,19 +1291,8 @@ struct dsi_regs {
#define DSI_PHY_TIME_3_CFG_CSR_TIME_REQRDY_MASK (0xff)
#define DSI_PHY_TIME_3_CFG_CSR_TIME_REQRDY_SHIFT 0
-/*
- * DSI timings
- * PXA988 has diffrent ESC CLK with MMP2/MMP3
- * it will be used in dsi_set_dphy() in pxa688_phy.c
- * as low power mode clock.
- */
-#ifdef CONFIG_CPU_PXA988
-#define DSI_ESC_CLK 52 /* Unit: Mhz */
-#define DSI_ESC_CLK_T 19 /* Unit: ns */
-#else
#define DSI_ESC_CLK 66 /* Unit: Mhz */
#define DSI_ESC_CLK_T 15 /* Unit: ns */
-#endif
/* LVDS */
/* LVDS_PHY_CTRL */
diff --git a/drivers/video/fbdev/mx3fb.c b/drivers/video/fbdev/mx3fb.c
index 142e860fb527..c645a0a0c341 100644
--- a/drivers/video/fbdev/mx3fb.c
+++ b/drivers/video/fbdev/mx3fb.c
@@ -27,6 +27,7 @@
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/dma/ipu-dma.h>
+#include <linux/backlight.h>
#include <linux/platform_data/dma-imx.h>
#include <linux/platform_data/video-mx3fb.h>
@@ -241,6 +242,7 @@ struct mx3fb_data {
void __iomem *reg_base;
spinlock_t lock;
struct device *dev;
+ struct backlight_device *bl;
uint32_t h_start_width;
uint32_t v_start_width;
@@ -271,6 +273,71 @@ struct mx3fb_info {
struct fb_var_screeninfo cur_var; /* current var info */
};
+static void sdc_set_brightness(struct mx3fb_data *mx3fb, uint8_t value);
+static u32 sdc_get_brightness(struct mx3fb_data *mx3fb);
+
+static int mx3fb_bl_get_brightness(struct backlight_device *bl)
+{
+ struct mx3fb_data *fbd = bl_get_data(bl);
+
+ return sdc_get_brightness(fbd);
+}
+
+static int mx3fb_bl_update_status(struct backlight_device *bl)
+{
+ struct mx3fb_data *fbd = bl_get_data(bl);
+ int brightness = bl->props.brightness;
+
+ if (bl->props.power != FB_BLANK_UNBLANK)
+ brightness = 0;
+ if (bl->props.fb_blank != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ fbd->backlight_level = (fbd->backlight_level & ~0xFF) | brightness;
+
+ sdc_set_brightness(fbd, fbd->backlight_level);
+
+ return 0;
+}
+
+static const struct backlight_ops mx3fb_lcdc_bl_ops = {
+ .update_status = mx3fb_bl_update_status,
+ .get_brightness = mx3fb_bl_get_brightness,
+};
+
+static void mx3fb_init_backlight(struct mx3fb_data *fbd)
+{
+ struct backlight_properties props;
+ struct backlight_device *bl;
+
+ if (fbd->bl)
+ return;
+
+ memset(&props, 0, sizeof(struct backlight_properties));
+ props.max_brightness = 0xff;
+ props.type = BACKLIGHT_RAW;
+ sdc_set_brightness(fbd, fbd->backlight_level);
+
+ bl = backlight_device_register("mx3fb-bl", fbd->dev, fbd,
+ &mx3fb_lcdc_bl_ops, &props);
+ if (IS_ERR(bl)) {
+ dev_err(fbd->dev, "error %ld on backlight register\n",
+ PTR_ERR(bl));
+ return;
+ }
+
+ fbd->bl = bl;
+ bl->props.power = FB_BLANK_UNBLANK;
+ bl->props.fb_blank = FB_BLANK_UNBLANK;
+ bl->props.brightness = mx3fb_bl_get_brightness(bl);
+}
+
+static void mx3fb_exit_backlight(struct mx3fb_data *fbd)
+{
+ if (fbd->bl)
+ backlight_device_unregister(fbd->bl);
+}
+
static void mx3fb_dma_done(void *);
/* Used fb-mode and bpp. Can be set on kernel command line, therefore file-static. */
@@ -628,6 +695,16 @@ static int sdc_set_global_alpha(struct mx3fb_data *mx3fb, bool enable, uint8_t a
return 0;
}
+static u32 sdc_get_brightness(struct mx3fb_data *mx3fb)
+{
+ u32 brightness;
+
+ brightness = mx3fb_read_reg(mx3fb, SDC_PWM_CTRL);
+ brightness = (brightness >> 16) & 0xFF;
+
+ return brightness;
+}
+
static void sdc_set_brightness(struct mx3fb_data *mx3fb, uint8_t value)
{
dev_dbg(mx3fb->dev, "%s: value = %d\n", __func__, value);
@@ -1496,7 +1573,7 @@ static int mx3fb_probe(struct platform_device *pdev)
if (!sdc_reg)
return -EINVAL;
- mx3fb = kzalloc(sizeof(*mx3fb), GFP_KERNEL);
+ mx3fb = devm_kzalloc(&pdev->dev, sizeof(*mx3fb), GFP_KERNEL);
if (!mx3fb)
return -ENOMEM;
@@ -1534,6 +1611,8 @@ static int mx3fb_probe(struct platform_device *pdev)
if (ret < 0)
goto eisdc0;
+ mx3fb_init_backlight(mx3fb);
+
return 0;
eisdc0:
@@ -1542,7 +1621,6 @@ ersdc0:
dmaengine_put();
iounmap(mx3fb->reg_base);
eremap:
- kfree(mx3fb);
dev_err(dev, "mx3fb: failed to register fb\n");
return ret;
}
@@ -1557,11 +1635,12 @@ static int mx3fb_remove(struct platform_device *dev)
chan = &mx3_fbi->idmac_channel->dma_chan;
release_fbi(fbi);
+ mx3fb_exit_backlight(mx3fb);
+
dma_release_channel(chan);
dmaengine_put();
iounmap(mx3fb->reg_base);
- kfree(mx3fb);
return 0;
}
diff --git a/drivers/video/fbdev/omap/Kconfig b/drivers/video/fbdev/omap/Kconfig
index 0bc3a936ce2b..18c4cb0d5690 100644
--- a/drivers/video/fbdev/omap/Kconfig
+++ b/drivers/video/fbdev/omap/Kconfig
@@ -39,6 +39,15 @@ config FB_OMAP_LCD_MIPID
the Mobile Industry Processor Interface DBI-C/DCS
specification. (Supported LCDs: Philips LPH8923, Sharp LS041Y3)
+config FB_OMAP_LCD_H3
+ bool "TPS65010 LCD controller on OMAP-H3"
+ depends on MACH_OMAP_H3
+ depends on TPS65010
+ default y
+ help
+ Say Y here if you want to have support for the LCD on the
+ H3 board.
+
config FB_OMAP_DMA_TUNE
bool "Set DMA SDRAM access priority high"
depends on FB_OMAP
diff --git a/drivers/video/fbdev/omap/Makefile b/drivers/video/fbdev/omap/Makefile
index 1927faffb5bc..732e0718be53 100644
--- a/drivers/video/fbdev/omap/Makefile
+++ b/drivers/video/fbdev/omap/Makefile
@@ -10,17 +10,18 @@ objs-y$(CONFIG_FB_OMAP_LCDC_EXTERNAL) += sossi.o
objs-y$(CONFIG_FB_OMAP_LCDC_HWA742) += hwa742.o
-objs-y$(CONFIG_MACH_AMS_DELTA) += lcd_ams_delta.o
-objs-y$(CONFIG_MACH_OMAP_H3) += lcd_h3.o
-objs-y$(CONFIG_MACH_OMAP_PALMTE) += lcd_palmte.o
-objs-y$(CONFIG_MACH_OMAP_PALMTT) += lcd_palmtt.o
-objs-y$(CONFIG_MACH_OMAP_PALMZ71) += lcd_palmz71.o
-objs-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o
-objs-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o
-objs-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
-
-objs-y$(CONFIG_FB_OMAP_LCD_MIPID) += lcd_mipid.o
-objs-y$(CONFIG_MACH_HERALD) += lcd_htcherald.o
+lcds-y$(CONFIG_MACH_AMS_DELTA) += lcd_ams_delta.o
+lcds-y$(CONFIG_FB_OMAP_LCD_H3) += lcd_h3.o
+lcds-y$(CONFIG_MACH_OMAP_PALMTE) += lcd_palmte.o
+lcds-y$(CONFIG_MACH_OMAP_PALMTT) += lcd_palmtt.o
+lcds-y$(CONFIG_MACH_OMAP_PALMZ71) += lcd_palmz71.o
+lcds-$(CONFIG_ARCH_OMAP16XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1610.o
+lcds-$(CONFIG_ARCH_OMAP15XX)$(CONFIG_MACH_OMAP_INNOVATOR) += lcd_inn1510.o
+lcds-y$(CONFIG_MACH_OMAP_OSK) += lcd_osk.o
+
+lcds-y$(CONFIG_FB_OMAP_LCD_MIPID) += lcd_mipid.o
+lcds-y$(CONFIG_MACH_HERALD) += lcd_htcherald.o
omapfb-objs := $(objs-yy)
+obj-$(CONFIG_FB_OMAP) += $(lcds-yy)
diff --git a/drivers/video/fbdev/omap/lcdc.c b/drivers/video/fbdev/omap/lcdc.c
index b52f62595f65..6efa2591eaa8 100644
--- a/drivers/video/fbdev/omap/lcdc.c
+++ b/drivers/video/fbdev/omap/lcdc.c
@@ -74,7 +74,6 @@ static struct omap_lcd_controller {
void (*dma_callback)(void *data);
void *dma_callback_data;
- int fbmem_allocated;
dma_addr_t vram_phys;
void *vram_virt;
unsigned long vram_size;
@@ -611,42 +610,6 @@ static void lcdc_dma_handler(u16 status, void *data)
lcdc.dma_callback(lcdc.dma_callback_data);
}
-static int mmap_kern(void)
-{
- struct vm_struct *kvma;
- struct vm_area_struct vma;
- pgprot_t pgprot;
- unsigned long vaddr;
-
- kvma = get_vm_area(lcdc.vram_size, VM_IOREMAP);
- if (kvma == NULL) {
- dev_err(lcdc.fbdev->dev, "can't get kernel vm area\n");
- return -ENOMEM;
- }
- vma.vm_mm = &init_mm;
-
- vaddr = (unsigned long)kvma->addr;
- vma.vm_start = vaddr;
- vma.vm_end = vaddr + lcdc.vram_size;
-
- pgprot = pgprot_writecombine(pgprot_kernel);
- if (io_remap_pfn_range(&vma, vaddr,
- lcdc.vram_phys >> PAGE_SHIFT,
- lcdc.vram_size, pgprot) < 0) {
- dev_err(lcdc.fbdev->dev, "kernel mmap for FB memory failed\n");
- return -EAGAIN;
- }
-
- lcdc.vram_virt = (void *)vaddr;
-
- return 0;
-}
-
-static void unmap_kern(void)
-{
- vunmap(lcdc.vram_virt);
-}
-
static int alloc_palette_ram(void)
{
lcdc.palette_virt = dma_alloc_writecombine(lcdc.fbdev->dev,
@@ -703,8 +666,6 @@ static void free_fbmem(void)
static int setup_fbmem(struct omapfb_mem_desc *req_md)
{
- int r;
-
if (!req_md->region_cnt) {
dev_err(lcdc.fbdev->dev, "no memory regions defined\n");
return -EINVAL;
@@ -715,31 +676,7 @@ static int setup_fbmem(struct omapfb_mem_desc *req_md)
req_md->region_cnt = 1;
}
- if (req_md->region[0].paddr == 0) {
- lcdc.fbmem_allocated = 1;
- if ((r = alloc_fbmem(&req_md->region[0])) < 0)
- return r;
- return 0;
- }
-
- lcdc.vram_phys = req_md->region[0].paddr;
- lcdc.vram_size = req_md->region[0].size;
-
- if ((r = mmap_kern()) < 0)
- return r;
-
- dev_dbg(lcdc.fbdev->dev, "vram at %08x size %08lx mapped to 0x%p\n",
- lcdc.vram_phys, lcdc.vram_size, lcdc.vram_virt);
-
- return 0;
-}
-
-static void cleanup_fbmem(void)
-{
- if (lcdc.fbmem_allocated)
- free_fbmem();
- else
- unmap_kern();
+ return alloc_fbmem(&req_md->region[0]);
}
static int omap_lcdc_init(struct omapfb_device *fbdev, int ext_mode,
@@ -833,7 +770,7 @@ static void omap_lcdc_cleanup(void)
{
if (!lcdc.ext_mode)
free_palette_ram();
- cleanup_fbmem();
+ free_fbmem();
omap_free_lcd_dma();
free_irq(OMAP_LCDC_IRQ, lcdc.fbdev);
clk_disable(lcdc.lcd_ck);
diff --git a/drivers/video/fbdev/omap/omapfb_main.c b/drivers/video/fbdev/omap/omapfb_main.c
index e4fc6d9b5371..d8d028d98711 100644
--- a/drivers/video/fbdev/omap/omapfb_main.c
+++ b/drivers/video/fbdev/omap/omapfb_main.c
@@ -1823,6 +1823,7 @@ void omapfb_register_panel(struct lcd_panel *panel)
if (fbdev_pdev != NULL)
omapfb_do_probe(fbdev_pdev, fbdev_panel);
}
+EXPORT_SYMBOL_GPL(omapfb_register_panel);
/* Called when the device is being detached from the driver */
static int omapfb_remove(struct platform_device *pdev)
diff --git a/drivers/video/fbdev/omap2/Makefile b/drivers/video/fbdev/omap2/Makefile
index bf8127df8c71..f8745ec369cc 100644
--- a/drivers/video/fbdev/omap2/Makefile
+++ b/drivers/video/fbdev/omap2/Makefile
@@ -1,5 +1,5 @@
obj-$(CONFIG_OMAP2_VRFB) += vrfb.o
-obj-$(CONFIG_OMAP2_DSS) += dss/
+obj-y += dss/
obj-y += displays-new/
obj-$(CONFIG_FB_OMAP2) += omapfb/
diff --git a/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c b/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c
index 29ed21b9dce5..4420ccb69aa9 100644
--- a/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c
+++ b/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c
@@ -13,6 +13,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <drm/drm_edid.h>
@@ -43,6 +44,8 @@ struct panel_drv_data {
struct device *dev;
struct omap_video_timings timings;
+
+ int hpd_gpio;
};
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
@@ -161,7 +164,10 @@ static bool hdmic_detect(struct omap_dss_device *dssdev)
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
- return in->ops.hdmi->detect(in);
+ if (gpio_is_valid(ddata->hpd_gpio))
+ return gpio_get_value_cansleep(ddata->hpd_gpio);
+ else
+ return in->ops.hdmi->detect(in);
}
static int hdmic_audio_enable(struct omap_dss_device *dssdev)
@@ -288,6 +294,8 @@ static int hdmic_probe_pdata(struct platform_device *pdev)
pdata = dev_get_platdata(&pdev->dev);
+ ddata->hpd_gpio = -ENODEV;
+
in = omap_dss_find_output(pdata->source);
if (in == NULL) {
dev_err(&pdev->dev, "Failed to find video source\n");
@@ -307,6 +315,14 @@ static int hdmic_probe_of(struct platform_device *pdev)
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct device_node *node = pdev->dev.of_node;
struct omap_dss_device *in;
+ int gpio;
+
+ /* HPD GPIO */
+ gpio = of_get_named_gpio(node, "hpd-gpios", 0);
+ if (gpio_is_valid(gpio))
+ ddata->hpd_gpio = gpio;
+ else
+ ddata->hpd_gpio = -ENODEV;
in = omapdss_of_find_source_for_first_ep(node);
if (IS_ERR(in)) {
@@ -344,6 +360,13 @@ static int hdmic_probe(struct platform_device *pdev)
return -ENODEV;
}
+ if (gpio_is_valid(ddata->hpd_gpio)) {
+ r = devm_gpio_request_one(&pdev->dev, ddata->hpd_gpio,
+ GPIOF_DIR_IN, "hdmi_hpd");
+ if (r)
+ goto err_reg;
+ }
+
ddata->timings = hdmic_default_timings;
dssdev = &ddata->dssdev;
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-dpi.c b/drivers/video/fbdev/omap2/displays-new/panel-dpi.c
index 5f8f7e7c81ef..3636b61dc9b4 100644
--- a/drivers/video/fbdev/omap2/displays-new/panel-dpi.c
+++ b/drivers/video/fbdev/omap2/displays-new/panel-dpi.c
@@ -13,9 +13,12 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <video/omapdss.h>
#include <video/omap-panel-data.h>
+#include <video/of_display_timing.h>
struct panel_drv_data {
struct omap_dss_device dssdev;
@@ -25,8 +28,10 @@ struct panel_drv_data {
struct omap_video_timings videomode;
+ /* used for non-DT boot, to be removed */
int backlight_gpio;
- int enable_gpio;
+
+ struct gpio_desc *enable_gpio;
};
#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
@@ -70,15 +75,16 @@ static int panel_dpi_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
- in->ops.dpi->set_data_lines(in, ddata->data_lines);
+ if (ddata->data_lines)
+ in->ops.dpi->set_data_lines(in, ddata->data_lines);
in->ops.dpi->set_timings(in, &ddata->videomode);
r = in->ops.dpi->enable(in);
if (r)
return r;
- if (gpio_is_valid(ddata->enable_gpio))
- gpio_set_value_cansleep(ddata->enable_gpio, 1);
+ if (ddata->enable_gpio)
+ gpiod_set_value_cansleep(ddata->enable_gpio, 1);
if (gpio_is_valid(ddata->backlight_gpio))
gpio_set_value_cansleep(ddata->backlight_gpio, 1);
@@ -96,8 +102,8 @@ static void panel_dpi_disable(struct omap_dss_device *dssdev)
if (!omapdss_device_is_enabled(dssdev))
return;
- if (gpio_is_valid(ddata->enable_gpio))
- gpio_set_value_cansleep(ddata->enable_gpio, 0);
+ if (ddata->enable_gpio)
+ gpiod_set_value_cansleep(ddata->enable_gpio, 0);
if (gpio_is_valid(ddata->backlight_gpio))
gpio_set_value_cansleep(ddata->backlight_gpio, 0);
@@ -156,6 +162,7 @@ static int panel_dpi_probe_pdata(struct platform_device *pdev)
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *dssdev, *in;
struct videomode vm;
+ int r;
pdata = dev_get_platdata(&pdev->dev);
@@ -176,10 +183,65 @@ static int panel_dpi_probe_pdata(struct platform_device *pdev)
dssdev = &ddata->dssdev;
dssdev->name = pdata->name;
- ddata->enable_gpio = pdata->enable_gpio;
+ r = devm_gpio_request_one(&pdev->dev, pdata->enable_gpio,
+ GPIOF_OUT_INIT_LOW, "panel enable");
+ if (r)
+ goto err_gpio;
+
+ ddata->enable_gpio = gpio_to_desc(pdata->enable_gpio);
+
ddata->backlight_gpio = pdata->backlight_gpio;
return 0;
+
+err_gpio:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int panel_dpi_probe_of(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct device_node *node = pdev->dev.of_node;
+ struct omap_dss_device *in;
+ int r;
+ struct display_timing timing;
+ struct videomode vm;
+ struct gpio_desc *gpio;
+
+ gpio = devm_gpiod_get(&pdev->dev, "enable");
+
+ if (IS_ERR(gpio)) {
+ if (PTR_ERR(gpio) != -ENOENT)
+ return PTR_ERR(gpio);
+ else
+ gpio = NULL;
+ } else {
+ gpiod_direction_output(gpio, 0);
+ }
+
+ ddata->enable_gpio = gpio;
+
+ ddata->backlight_gpio = -ENOENT;
+
+ r = of_get_display_timing(node, "panel-timing", &timing);
+ if (r) {
+ dev_err(&pdev->dev, "failed to get video timing\n");
+ return r;
+ }
+
+ videomode_from_timing(&timing, &vm);
+ videomode_to_omap_video_timings(&vm, &ddata->videomode);
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&pdev->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ return 0;
}
static int panel_dpi_probe(struct platform_device *pdev)
@@ -198,17 +260,14 @@ static int panel_dpi_probe(struct platform_device *pdev)
r = panel_dpi_probe_pdata(pdev);
if (r)
return r;
+ } else if (pdev->dev.of_node) {
+ r = panel_dpi_probe_of(pdev);
+ if (r)
+ return r;
} else {
return -ENODEV;
}
- if (gpio_is_valid(ddata->enable_gpio)) {
- r = devm_gpio_request_one(&pdev->dev, ddata->enable_gpio,
- GPIOF_OUT_INIT_LOW, "panel enable");
- if (r)
- goto err_gpio;
- }
-
if (gpio_is_valid(ddata->backlight_gpio)) {
r = devm_gpio_request_one(&pdev->dev, ddata->backlight_gpio,
GPIOF_OUT_INIT_LOW, "panel backlight");
@@ -254,12 +313,20 @@ static int __exit panel_dpi_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id panel_dpi_of_match[] = {
+ { .compatible = "omapdss,panel-dpi", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, panel_dpi_of_match);
+
static struct platform_driver panel_dpi_driver = {
.probe = panel_dpi_probe,
.remove = __exit_p(panel_dpi_remove),
.driver = {
.name = "panel-dpi",
.owner = THIS_MODULE,
+ .of_match_table = panel_dpi_of_match,
},
};
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c b/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c
index 2e6b513222d9..cc5b5124e0b4 100644
--- a/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c
+++ b/drivers/video/fbdev/omap2/displays-new/panel-lgphilips-lb035q02.c
@@ -50,9 +50,10 @@ struct panel_drv_data {
struct omap_video_timings videomode;
- int reset_gpio;
+ /* used for non-DT boot, to be removed */
int backlight_gpio;
- int enable_gpio;
+
+ struct gpio_desc *enable_gpio;
};
#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
@@ -158,15 +159,16 @@ static int lb035q02_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
- in->ops.dpi->set_data_lines(in, ddata->data_lines);
+ if (ddata->data_lines)
+ in->ops.dpi->set_data_lines(in, ddata->data_lines);
in->ops.dpi->set_timings(in, &ddata->videomode);
r = in->ops.dpi->enable(in);
if (r)
return r;
- if (gpio_is_valid(ddata->enable_gpio))
- gpio_set_value_cansleep(ddata->enable_gpio, 1);
+ if (ddata->enable_gpio)
+ gpiod_set_value_cansleep(ddata->enable_gpio, 1);
if (gpio_is_valid(ddata->backlight_gpio))
gpio_set_value_cansleep(ddata->backlight_gpio, 1);
@@ -184,8 +186,8 @@ static void lb035q02_disable(struct omap_dss_device *dssdev)
if (!omapdss_device_is_enabled(dssdev))
return;
- if (gpio_is_valid(ddata->enable_gpio))
- gpio_set_value_cansleep(ddata->enable_gpio, 0);
+ if (ddata->enable_gpio)
+ gpiod_set_value_cansleep(ddata->enable_gpio, 0);
if (gpio_is_valid(ddata->backlight_gpio))
gpio_set_value_cansleep(ddata->backlight_gpio, 0);
@@ -243,6 +245,7 @@ static int lb035q02_probe_pdata(struct spi_device *spi)
const struct panel_lb035q02_platform_data *pdata;
struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
struct omap_dss_device *dssdev, *in;
+ int r;
pdata = dev_get_platdata(&spi->dev);
@@ -260,10 +263,48 @@ static int lb035q02_probe_pdata(struct spi_device *spi)
dssdev = &ddata->dssdev;
dssdev->name = pdata->name;
- ddata->enable_gpio = pdata->enable_gpio;
+ r = devm_gpio_request_one(&spi->dev, pdata->enable_gpio,
+ GPIOF_OUT_INIT_LOW, "panel enable");
+ if (r)
+ goto err_gpio;
+
+ ddata->enable_gpio = gpio_to_desc(pdata->enable_gpio);
+
ddata->backlight_gpio = pdata->backlight_gpio;
return 0;
+err_gpio:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int lb035q02_probe_of(struct spi_device *spi)
+{
+ struct device_node *node = spi->dev.of_node;
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *in;
+ struct gpio_desc *gpio;
+
+ gpio = devm_gpiod_get(&spi->dev, "enable");
+ if (IS_ERR(gpio)) {
+ dev_err(&spi->dev, "failed to parse enable gpio\n");
+ return PTR_ERR(gpio);
+ } else {
+ gpiod_direction_output(gpio, 0);
+ ddata->enable_gpio = gpio;
+ }
+
+ ddata->backlight_gpio = -ENOENT;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&spi->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ return 0;
}
static int lb035q02_panel_spi_probe(struct spi_device *spi)
@@ -284,17 +325,14 @@ static int lb035q02_panel_spi_probe(struct spi_device *spi)
r = lb035q02_probe_pdata(spi);
if (r)
return r;
+ } else if (spi->dev.of_node) {
+ r = lb035q02_probe_of(spi);
+ if (r)
+ return r;
} else {
return -ENODEV;
}
- if (gpio_is_valid(ddata->enable_gpio)) {
- r = devm_gpio_request_one(&spi->dev, ddata->enable_gpio,
- GPIOF_OUT_INIT_LOW, "panel enable");
- if (r)
- goto err_gpio;
- }
-
if (gpio_is_valid(ddata->backlight_gpio)) {
r = devm_gpio_request_one(&spi->dev, ddata->backlight_gpio,
GPIOF_OUT_INIT_LOW, "panel backlight");
@@ -342,17 +380,26 @@ static int lb035q02_panel_spi_remove(struct spi_device *spi)
return 0;
}
+static const struct of_device_id lb035q02_of_match[] = {
+ { .compatible = "omapdss,lgphilips,lb035q02", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, lb035q02_of_match);
+
static struct spi_driver lb035q02_spi_driver = {
.probe = lb035q02_panel_spi_probe,
.remove = lb035q02_panel_spi_remove,
.driver = {
.name = "panel_lgphilips_lb035q02",
.owner = THIS_MODULE,
+ .of_match_table = lb035q02_of_match,
},
};
module_spi_driver(lb035q02_spi_driver);
+MODULE_ALIAS("spi:lgphilips,lb035q02");
MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ti.com>");
MODULE_DESCRIPTION("LG.Philips LB035Q02 LCD Panel driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-nec-nl8048hl11.c b/drivers/video/fbdev/omap2/displays-new/panel-nec-nl8048hl11.c
index 996fa004b48c..3595f111aa35 100644
--- a/drivers/video/fbdev/omap2/displays-new/panel-nec-nl8048hl11.c
+++ b/drivers/video/fbdev/omap2/displays-new/panel-nec-nl8048hl11.c
@@ -16,6 +16,7 @@
#include <linux/spi/spi.h>
#include <linux/fb.h>
#include <linux/gpio.h>
+#include <linux/of_gpio.h>
#include <video/omapdss.h>
#include <video/omap-panel-data.h>
@@ -156,7 +157,8 @@ static int nec_8048_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
- in->ops.dpi->set_data_lines(in, ddata->data_lines);
+ if (ddata->data_lines)
+ in->ops.dpi->set_data_lines(in, ddata->data_lines);
in->ops.dpi->set_timings(in, &ddata->videomode);
r = in->ops.dpi->enable(in);
@@ -258,6 +260,34 @@ static int nec_8048_probe_pdata(struct spi_device *spi)
return 0;
}
+static int nec_8048_probe_of(struct spi_device *spi)
+{
+ struct device_node *node = spi->dev.of_node;
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *in;
+ int gpio;
+
+ gpio = of_get_named_gpio(node, "reset-gpios", 0);
+ if (!gpio_is_valid(gpio)) {
+ dev_err(&spi->dev, "failed to parse enable gpio\n");
+ return gpio;
+ }
+ ddata->res_gpio = gpio;
+
+ /* XXX the panel spec doesn't mention any QVGA pin?? */
+ ddata->qvga_gpio = -ENOENT;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&spi->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ return 0;
+}
+
static int nec_8048_probe(struct spi_device *spi)
{
struct panel_drv_data *ddata;
@@ -289,6 +319,10 @@ static int nec_8048_probe(struct spi_device *spi)
r = nec_8048_probe_pdata(spi);
if (r)
return r;
+ } else if (spi->dev.of_node) {
+ r = nec_8048_probe_of(spi);
+ if (r)
+ return r;
} else {
return -ENODEV;
}
@@ -377,11 +411,19 @@ static SIMPLE_DEV_PM_OPS(nec_8048_pm_ops, nec_8048_suspend,
#define NEC_8048_PM_OPS NULL
#endif
+static const struct of_device_id nec_8048_of_match[] = {
+ { .compatible = "omapdss,nec,nl8048hl11", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, nec_8048_of_match);
+
static struct spi_driver nec_8048_driver = {
.driver = {
.name = "panel-nec-nl8048hl11",
.owner = THIS_MODULE,
.pm = NEC_8048_PM_OPS,
+ .of_match_table = nec_8048_of_match,
},
.probe = nec_8048_probe,
.remove = nec_8048_remove,
@@ -389,6 +431,7 @@ static struct spi_driver nec_8048_driver = {
module_spi_driver(nec_8048_driver);
+MODULE_ALIAS("spi:nec,nl8048hl11");
MODULE_AUTHOR("Erik Gilling <konkers@android.com>");
MODULE_DESCRIPTION("NEC-NL8048HL11 Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c b/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c
index b2f710be565d..f1f72ce50a17 100644
--- a/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c
+++ b/drivers/video/fbdev/omap2/displays-new/panel-sharp-ls037v7dw01.c
@@ -12,25 +12,28 @@
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-
+#include <linux/regulator/consumer.h>
#include <video/omapdss.h>
#include <video/omap-panel-data.h>
struct panel_drv_data {
struct omap_dss_device dssdev;
struct omap_dss_device *in;
+ struct regulator *vcc;
int data_lines;
struct omap_video_timings videomode;
- int resb_gpio;
- int ini_gpio;
- int mo_gpio;
- int lr_gpio;
- int ud_gpio;
+ struct gpio_desc *resb_gpio; /* low = reset active min 20 us */
+ struct gpio_desc *ini_gpio; /* high = power on */
+ struct gpio_desc *mo_gpio; /* low = 480x640, high = 240x320 */
+ struct gpio_desc *lr_gpio; /* high = conventional horizontal scanning */
+ struct gpio_desc *ud_gpio; /* high = conventional vertical scanning */
};
static const struct omap_video_timings sharp_ls_timings = {
@@ -95,21 +98,30 @@ static int sharp_ls_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
- in->ops.dpi->set_data_lines(in, ddata->data_lines);
+ if (ddata->data_lines)
+ in->ops.dpi->set_data_lines(in, ddata->data_lines);
in->ops.dpi->set_timings(in, &ddata->videomode);
+ if (ddata->vcc) {
+ r = regulator_enable(ddata->vcc);
+ if (r != 0)
+ return r;
+ }
+
r = in->ops.dpi->enable(in);
- if (r)
+ if (r) {
+ regulator_disable(ddata->vcc);
return r;
+ }
/* wait couple of vsyncs until enabling the LCD */
msleep(50);
- if (gpio_is_valid(ddata->resb_gpio))
- gpio_set_value_cansleep(ddata->resb_gpio, 1);
+ if (ddata->resb_gpio)
+ gpiod_set_value_cansleep(ddata->resb_gpio, 1);
- if (gpio_is_valid(ddata->ini_gpio))
- gpio_set_value_cansleep(ddata->ini_gpio, 1);
+ if (ddata->ini_gpio)
+ gpiod_set_value_cansleep(ddata->ini_gpio, 1);
dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
@@ -124,11 +136,11 @@ static void sharp_ls_disable(struct omap_dss_device *dssdev)
if (!omapdss_device_is_enabled(dssdev))
return;
- if (gpio_is_valid(ddata->ini_gpio))
- gpio_set_value_cansleep(ddata->ini_gpio, 0);
+ if (ddata->ini_gpio)
+ gpiod_set_value_cansleep(ddata->ini_gpio, 0);
- if (gpio_is_valid(ddata->resb_gpio))
- gpio_set_value_cansleep(ddata->resb_gpio, 0);
+ if (ddata->resb_gpio)
+ gpiod_set_value_cansleep(ddata->resb_gpio, 0);
/* wait at least 5 vsyncs after disabling the LCD */
@@ -136,6 +148,9 @@ static void sharp_ls_disable(struct omap_dss_device *dssdev)
in->ops.dpi->disable(in);
+ if (ddata->vcc)
+ regulator_disable(ddata->vcc);
+
dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
}
@@ -182,11 +197,32 @@ static struct omap_dss_driver sharp_ls_ops = {
.get_resolution = omapdss_default_get_resolution,
};
+static int sharp_ls_get_gpio(struct device *dev, int gpio, unsigned long flags,
+ char *desc, struct gpio_desc **gpiod)
+{
+ struct gpio_desc *gd;
+ int r;
+
+ *gpiod = NULL;
+
+ r = devm_gpio_request_one(dev, gpio, flags, desc);
+ if (r)
+ return r == -ENOENT ? 0 : r;
+
+ gd = gpio_to_desc(gpio);
+ if (IS_ERR(gd))
+ return PTR_ERR(gd) == -ENOENT ? 0 : PTR_ERR(gd);
+
+ *gpiod = gd;
+ return 0;
+}
+
static int sharp_ls_probe_pdata(struct platform_device *pdev)
{
const struct panel_sharp_ls037v7dw01_platform_data *pdata;
struct panel_drv_data *ddata = platform_get_drvdata(pdev);
struct omap_dss_device *dssdev, *in;
+ int r;
pdata = dev_get_platdata(&pdev->dev);
@@ -204,11 +240,95 @@ static int sharp_ls_probe_pdata(struct platform_device *pdev)
dssdev = &ddata->dssdev;
dssdev->name = pdata->name;
- ddata->resb_gpio = pdata->resb_gpio;
- ddata->ini_gpio = pdata->ini_gpio;
- ddata->mo_gpio = pdata->mo_gpio;
- ddata->lr_gpio = pdata->lr_gpio;
- ddata->ud_gpio = pdata->ud_gpio;
+ r = sharp_ls_get_gpio(&pdev->dev, pdata->mo_gpio, GPIOF_OUT_INIT_LOW,
+ "lcd MO", &ddata->mo_gpio);
+ if (r)
+ return r;
+ r = sharp_ls_get_gpio(&pdev->dev, pdata->lr_gpio, GPIOF_OUT_INIT_HIGH,
+ "lcd LR", &ddata->lr_gpio);
+ if (r)
+ return r;
+ r = sharp_ls_get_gpio(&pdev->dev, pdata->ud_gpio, GPIOF_OUT_INIT_HIGH,
+ "lcd UD", &ddata->ud_gpio);
+ if (r)
+ return r;
+ r = sharp_ls_get_gpio(&pdev->dev, pdata->resb_gpio, GPIOF_OUT_INIT_LOW,
+ "lcd RESB", &ddata->resb_gpio);
+ if (r)
+ return r;
+ r = sharp_ls_get_gpio(&pdev->dev, pdata->ini_gpio, GPIOF_OUT_INIT_LOW,
+ "lcd INI", &ddata->ini_gpio);
+ if (r)
+ return r;
+
+ return 0;
+}
+
+static int sharp_ls_get_gpio_of(struct device *dev, int index, int val,
+ const char *desc, struct gpio_desc **gpiod)
+{
+ struct gpio_desc *gd;
+ int r;
+
+ *gpiod = NULL;
+
+ gd = devm_gpiod_get_index(dev, desc, index);
+ if (IS_ERR(gd))
+ return PTR_ERR(gd) == -ENOENT ? 0 : PTR_ERR(gd);
+
+ r = gpiod_direction_output(gd, val);
+ if (r)
+ return r;
+
+ *gpiod = gd;
+ return 0;
+}
+
+static int sharp_ls_probe_of(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct device_node *node = pdev->dev.of_node;
+ struct omap_dss_device *in;
+ int r;
+
+ ddata->vcc = devm_regulator_get(&pdev->dev, "envdd");
+ if (IS_ERR(ddata->vcc)) {
+ dev_err(&pdev->dev, "failed to get regulator\n");
+ return PTR_ERR(ddata->vcc);
+ }
+
+ /* lcd INI */
+ r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "enable", &ddata->ini_gpio);
+ if (r)
+ return r;
+
+ /* lcd RESB */
+ r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "reset", &ddata->resb_gpio);
+ if (r)
+ return r;
+
+ /* lcd MO */
+ r = sharp_ls_get_gpio_of(&pdev->dev, 0, 0, "mode", &ddata->mo_gpio);
+ if (r)
+ return r;
+
+ /* lcd LR */
+ r = sharp_ls_get_gpio_of(&pdev->dev, 1, 1, "mode", &ddata->lr_gpio);
+ if (r)
+ return r;
+
+ /* lcd UD */
+ r = sharp_ls_get_gpio_of(&pdev->dev, 2, 1, "mode", &ddata->ud_gpio);
+ if (r)
+ return r;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&pdev->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
return 0;
}
@@ -229,45 +349,14 @@ static int sharp_ls_probe(struct platform_device *pdev)
r = sharp_ls_probe_pdata(pdev);
if (r)
return r;
+ } else if (pdev->dev.of_node) {
+ r = sharp_ls_probe_of(pdev);
+ if (r)
+ return r;
} else {
return -ENODEV;
}
- if (gpio_is_valid(ddata->mo_gpio)) {
- r = devm_gpio_request_one(&pdev->dev, ddata->mo_gpio,
- GPIOF_OUT_INIT_LOW, "lcd MO");
- if (r)
- goto err_gpio;
- }
-
- if (gpio_is_valid(ddata->lr_gpio)) {
- r = devm_gpio_request_one(&pdev->dev, ddata->lr_gpio,
- GPIOF_OUT_INIT_HIGH, "lcd LR");
- if (r)
- goto err_gpio;
- }
-
- if (gpio_is_valid(ddata->ud_gpio)) {
- r = devm_gpio_request_one(&pdev->dev, ddata->ud_gpio,
- GPIOF_OUT_INIT_HIGH, "lcd UD");
- if (r)
- goto err_gpio;
- }
-
- if (gpio_is_valid(ddata->resb_gpio)) {
- r = devm_gpio_request_one(&pdev->dev, ddata->resb_gpio,
- GPIOF_OUT_INIT_LOW, "lcd RESB");
- if (r)
- goto err_gpio;
- }
-
- if (gpio_is_valid(ddata->ini_gpio)) {
- r = devm_gpio_request_one(&pdev->dev, ddata->ini_gpio,
- GPIOF_OUT_INIT_LOW, "lcd INI");
- if (r)
- goto err_gpio;
- }
-
ddata->videomode = sharp_ls_timings;
dssdev = &ddata->dssdev;
@@ -287,7 +376,6 @@ static int sharp_ls_probe(struct platform_device *pdev)
return 0;
err_reg:
-err_gpio:
omap_dss_put_device(ddata->in);
return r;
}
@@ -308,12 +396,20 @@ static int __exit sharp_ls_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id sharp_ls_of_match[] = {
+ { .compatible = "omapdss,sharp,ls037v7dw01", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, sharp_ls_of_match);
+
static struct platform_driver sharp_ls_driver = {
.probe = sharp_ls_probe,
.remove = __exit_p(sharp_ls_remove),
.driver = {
.name = "panel-sharp-ls037v7dw01",
.owner = THIS_MODULE,
+ .of_match_table = sharp_ls_of_match,
},
};
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c b/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c
index fae6adc005a7..728808bcceeb 100644
--- a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c
+++ b/drivers/video/fbdev/omap2/displays-new/panel-tpo-td028ttec1.c
@@ -206,7 +206,8 @@ static int td028ttec1_panel_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
- in->ops.dpi->set_data_lines(in, ddata->data_lines);
+ if (ddata->data_lines)
+ in->ops.dpi->set_data_lines(in, ddata->data_lines);
in->ops.dpi->set_timings(in, &ddata->videomode);
r = in->ops.dpi->enable(in);
@@ -389,6 +390,23 @@ static int td028ttec1_panel_probe_pdata(struct spi_device *spi)
return 0;
}
+static int td028ttec1_probe_of(struct spi_device *spi)
+{
+ struct device_node *node = spi->dev.of_node;
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *in;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&spi->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ return 0;
+}
+
static int td028ttec1_panel_probe(struct spi_device *spi)
{
struct panel_drv_data *ddata;
@@ -418,6 +436,10 @@ static int td028ttec1_panel_probe(struct spi_device *spi)
r = td028ttec1_panel_probe_pdata(spi);
if (r)
return r;
+ } else if (spi->dev.of_node) {
+ r = td028ttec1_probe_of(spi);
+ if (r)
+ return r;
} else {
return -ENODEV;
}
@@ -463,6 +485,13 @@ static int td028ttec1_panel_remove(struct spi_device *spi)
return 0;
}
+static const struct of_device_id td028ttec1_of_match[] = {
+ { .compatible = "omapdss,toppoly,td028ttec1", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, td028ttec1_of_match);
+
static struct spi_driver td028ttec1_spi_driver = {
.probe = td028ttec1_panel_probe,
.remove = td028ttec1_panel_remove,
@@ -470,11 +499,13 @@ static struct spi_driver td028ttec1_spi_driver = {
.driver = {
.name = "panel-tpo-td028ttec1",
.owner = THIS_MODULE,
+ .of_match_table = td028ttec1_of_match,
},
};
module_spi_driver(td028ttec1_spi_driver);
+MODULE_ALIAS("spi:toppoly,td028ttec1");
MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>");
MODULE_DESCRIPTION("Toppoly TD028TTEC1 panel driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c b/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c
index 875b40263b33..de78ab0caaa8 100644
--- a/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c
+++ b/drivers/video/fbdev/omap2/displays-new/panel-tpo-td043mtea1.c
@@ -17,6 +17,7 @@
#include <linux/gpio.h>
#include <linux/err.h>
#include <linux/slab.h>
+#include <linux/of_gpio.h>
#include <video/omapdss.h>
#include <video/omap-panel-data.h>
@@ -376,7 +377,8 @@ static int tpo_td043_enable(struct omap_dss_device *dssdev)
if (omapdss_device_is_enabled(dssdev))
return 0;
- in->ops.dpi->set_data_lines(in, ddata->data_lines);
+ if (ddata->data_lines)
+ in->ops.dpi->set_data_lines(in, ddata->data_lines);
in->ops.dpi->set_timings(in, &ddata->videomode);
r = in->ops.dpi->enable(in);
@@ -489,6 +491,31 @@ static int tpo_td043_probe_pdata(struct spi_device *spi)
return 0;
}
+static int tpo_td043_probe_of(struct spi_device *spi)
+{
+ struct device_node *node = spi->dev.of_node;
+ struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+ struct omap_dss_device *in;
+ int gpio;
+
+ gpio = of_get_named_gpio(node, "reset-gpios", 0);
+ if (!gpio_is_valid(gpio)) {
+ dev_err(&spi->dev, "failed to parse enable gpio\n");
+ return gpio;
+ }
+ ddata->nreset_gpio = gpio;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&spi->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ return 0;
+}
+
static int tpo_td043_probe(struct spi_device *spi)
{
struct panel_drv_data *ddata;
@@ -518,6 +545,10 @@ static int tpo_td043_probe(struct spi_device *spi)
r = tpo_td043_probe_pdata(spi);
if (r)
return r;
+ } else if (spi->dev.of_node) {
+ r = tpo_td043_probe_of(spi);
+ if (r)
+ return r;
} else {
return -ENODEV;
}
@@ -629,11 +660,19 @@ static int tpo_td043_spi_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(tpo_td043_spi_pm,
tpo_td043_spi_suspend, tpo_td043_spi_resume);
+static const struct of_device_id tpo_td043_of_match[] = {
+ { .compatible = "omapdss,tpo,td043mtea1", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, tpo_td043_of_match);
+
static struct spi_driver tpo_td043_spi_driver = {
.driver = {
.name = "panel-tpo-td043mtea1",
.owner = THIS_MODULE,
.pm = &tpo_td043_spi_pm,
+ .of_match_table = tpo_td043_of_match,
},
.probe = tpo_td043_probe,
.remove = tpo_td043_remove,
@@ -641,6 +680,7 @@ static struct spi_driver tpo_td043_spi_driver = {
module_spi_driver(tpo_td043_spi_driver);
+MODULE_ALIAS("spi:tpo,td043mtea1");
MODULE_AUTHOR("GraĹľvydas Ignotas <notasas@gmail.com>");
MODULE_DESCRIPTION("TPO TD043MTEA1 LCD Driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/video/fbdev/omap2/dss/Kconfig b/drivers/video/fbdev/omap2/dss/Kconfig
index dde4281663b1..285bcd103dce 100644
--- a/drivers/video/fbdev/omap2/dss/Kconfig
+++ b/drivers/video/fbdev/omap2/dss/Kconfig
@@ -1,6 +1,10 @@
+config OMAP2_DSS_INIT
+ bool
+
menuconfig OMAP2_DSS
tristate "OMAP2+ Display Subsystem support"
select VIDEOMODE_HELPERS
+ select OMAP2_DSS_INIT
help
OMAP2+ Display Subsystem support.
@@ -59,16 +63,32 @@ config OMAP2_DSS_VENC
help
OMAP Video Encoder support for S-Video and composite TV-out.
+config OMAP2_DSS_HDMI_COMMON
+ bool
+
config OMAP4_DSS_HDMI
- bool "HDMI support"
+ bool "HDMI support for OMAP4"
default y
+ select OMAP2_DSS_HDMI_COMMON
help
- HDMI Interface. This adds the High Definition Multimedia Interface.
- See http://www.hdmi.org/ for HDMI specification.
+ HDMI support for OMAP4 based SoCs.
config OMAP4_DSS_HDMI_AUDIO
bool
+config OMAP5_DSS_HDMI
+ bool "HDMI support for OMAP5"
+ default n
+ select OMAP2_DSS_HDMI_COMMON
+ help
+ HDMI Interface for OMAP5 and similar cores. This adds the High
+ Definition Multimedia Interface. See http://www.hdmi.org/ for HDMI
+ specification.
+
+config OMAP5_DSS_HDMI_AUDIO
+ depends on OMAP5_DSS_HDMI
+ bool
+
config OMAP2_DSS_SDI
bool "SDI support"
default n
diff --git a/drivers/video/fbdev/omap2/dss/Makefile b/drivers/video/fbdev/omap2/dss/Makefile
index 8aec8bda27cc..245f933060ee 100644
--- a/drivers/video/fbdev/omap2/dss/Makefile
+++ b/drivers/video/fbdev/omap2/dss/Makefile
@@ -1,3 +1,4 @@
+obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
# Core DSS files
omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
@@ -10,6 +11,8 @@ omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o
omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o
omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o
omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o
-omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi4.o hdmi_common.o hdmi_wp.o hdmi_pll.o \
- hdmi_phy.o hdmi4_core.o
+omapdss-$(CONFIG_OMAP2_DSS_HDMI_COMMON) += hdmi_common.o hdmi_wp.o hdmi_pll.o \
+ hdmi_phy.o
+omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi4.o hdmi4_core.o
+omapdss-$(CONFIG_OMAP5_DSS_HDMI) += hdmi5.o hdmi5_core.o
ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG
diff --git a/drivers/video/fbdev/omap2/dss/core.c b/drivers/video/fbdev/omap2/dss/core.c
index ffa45c894cd4..6b74f73fb524 100644
--- a/drivers/video/fbdev/omap2/dss/core.c
+++ b/drivers/video/fbdev/omap2/dss/core.c
@@ -268,6 +268,9 @@ static int (*dss_output_drv_reg_funcs[])(void) __initdata = {
#ifdef CONFIG_OMAP4_DSS_HDMI
hdmi4_init_platform_driver,
#endif
+#ifdef CONFIG_OMAP5_DSS_HDMI
+ hdmi5_init_platform_driver,
+#endif
};
static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = {
@@ -289,6 +292,9 @@ static void (*dss_output_drv_unreg_funcs[])(void) __exitdata = {
#ifdef CONFIG_OMAP4_DSS_HDMI
hdmi4_uninit_platform_driver,
#endif
+#ifdef CONFIG_OMAP5_DSS_HDMI
+ hdmi5_uninit_platform_driver,
+#endif
};
static bool dss_output_drv_loaded[ARRAY_SIZE(dss_output_drv_reg_funcs)];
diff --git a/drivers/video/fbdev/omap2/dss/dispc.c b/drivers/video/fbdev/omap2/dss/dispc.c
index f18397c33e8f..7aa33b0f4a1f 100644
--- a/drivers/video/fbdev/omap2/dss/dispc.c
+++ b/drivers/video/fbdev/omap2/dss/dispc.c
@@ -2577,9 +2577,9 @@ int dispc_ovl_setup(enum omap_plane plane, const struct omap_overlay_info *oi,
channel = dispc_ovl_get_channel_out(plane);
- DSSDBG("dispc_ovl_setup %d, pa %x, pa_uv %x, sw %d, %d,%d, %dx%d -> "
- "%dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n",
- plane, oi->paddr, oi->p_uv_addr, oi->screen_width, oi->pos_x,
+ DSSDBG("dispc_ovl_setup %d, pa %pad, pa_uv %pad, sw %d, %d,%d, %dx%d ->"
+ " %dx%d, cmode %x, rot %d, mir %d, chan %d repl %d\n",
+ plane, &oi->paddr, &oi->p_uv_addr, oi->screen_width, oi->pos_x,
oi->pos_y, oi->width, oi->height, oi->out_width, oi->out_height,
oi->color_mode, oi->rotation, oi->mirror, channel, replication);
@@ -2945,13 +2945,13 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
BUG();
}
- l = dispc_read_reg(DISPC_POL_FREQ(channel));
- l |= FLD_VAL(onoff, 17, 17);
- l |= FLD_VAL(rf, 16, 16);
- l |= FLD_VAL(de_level, 15, 15);
- l |= FLD_VAL(ipc, 14, 14);
- l |= FLD_VAL(hsync_level, 13, 13);
- l |= FLD_VAL(vsync_level, 12, 12);
+ l = FLD_VAL(onoff, 17, 17) |
+ FLD_VAL(rf, 16, 16) |
+ FLD_VAL(de_level, 15, 15) |
+ FLD_VAL(ipc, 14, 14) |
+ FLD_VAL(hsync_level, 13, 13) |
+ FLD_VAL(vsync_level, 12, 12);
+
dispc_write_reg(DISPC_POL_FREQ(channel), l);
}
@@ -3656,6 +3656,7 @@ static int __init dispc_init_features(struct platform_device *pdev)
case OMAPDSS_VER_OMAP34xx_ES3:
case OMAPDSS_VER_OMAP3630:
case OMAPDSS_VER_AM35xx:
+ case OMAPDSS_VER_AM43xx:
src = &omap34xx_rev3_0_dispc_feats;
break;
@@ -3829,6 +3830,7 @@ static const struct of_device_id dispc_of_match[] = {
{ .compatible = "ti,omap2-dispc", },
{ .compatible = "ti,omap3-dispc", },
{ .compatible = "ti,omap4-dispc", },
+ { .compatible = "ti,omap5-dispc", },
{},
};
diff --git a/drivers/video/fbdev/omap2/dss/dpi.c b/drivers/video/fbdev/omap2/dss/dpi.c
index 157921db447a..9368972d6962 100644
--- a/drivers/video/fbdev/omap2/dss/dpi.c
+++ b/drivers/video/fbdev/omap2/dss/dpi.c
@@ -67,6 +67,7 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
case OMAPDSS_VER_OMAP34xx_ES3:
case OMAPDSS_VER_OMAP3630:
case OMAPDSS_VER_AM35xx:
+ case OMAPDSS_VER_AM43xx:
return NULL;
case OMAPDSS_VER_OMAP4430_ES1:
@@ -103,6 +104,8 @@ static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC;
case OMAP_DSS_CHANNEL_LCD2:
return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
+ case OMAP_DSS_CHANNEL_LCD3:
+ return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
default:
/* this shouldn't happen */
WARN_ON(1);
@@ -595,6 +598,7 @@ static enum omap_channel dpi_get_channel(void)
case OMAPDSS_VER_OMAP34xx_ES3:
case OMAPDSS_VER_OMAP3630:
case OMAPDSS_VER_AM35xx:
+ case OMAPDSS_VER_AM43xx:
return OMAP_DSS_CHANNEL_LCD;
case OMAPDSS_VER_OMAP4430_ES1:
diff --git a/drivers/video/fbdev/omap2/dss/dsi.c b/drivers/video/fbdev/omap2/dss/dsi.c
index 8be9b04d8849..4755a34a5422 100644
--- a/drivers/video/fbdev/omap2/dss/dsi.c
+++ b/drivers/video/fbdev/omap2/dss/dsi.c
@@ -1161,6 +1161,7 @@ static int dsi_regulator_init(struct platform_device *dsidev)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
struct regulator *vdds_dsi;
+ int r;
if (dsi->vdds_dsi_reg != NULL)
return 0;
@@ -1173,6 +1174,15 @@ static int dsi_regulator_init(struct platform_device *dsidev)
return PTR_ERR(vdds_dsi);
}
+ if (regulator_can_change_voltage(vdds_dsi)) {
+ r = regulator_set_voltage(vdds_dsi, 1800000, 1800000);
+ if (r) {
+ devm_regulator_put(vdds_dsi);
+ DSSERR("can't set the DSI regulator voltage\n");
+ return r;
+ }
+ }
+
dsi->vdds_dsi_reg = vdds_dsi;
return 0;
@@ -5122,6 +5132,7 @@ static enum omap_channel dsi_get_channel(int module_id)
{
switch (omapdss_get_version()) {
case OMAPDSS_VER_OMAP24xx:
+ case OMAPDSS_VER_AM43xx:
DSSWARN("DSI not supported\n");
return OMAP_DSS_CHANNEL_LCD;
@@ -5723,9 +5734,16 @@ static const struct dsi_module_id_data dsi_of_data_omap4[] = {
{ },
};
+static const struct dsi_module_id_data dsi_of_data_omap5[] = {
+ { .address = 0x58004000, .id = 0, },
+ { .address = 0x58009000, .id = 1, },
+ { },
+};
+
static const struct of_device_id dsi_of_match[] = {
{ .compatible = "ti,omap3-dsi", .data = dsi_of_data_omap3, },
{ .compatible = "ti,omap4-dsi", .data = dsi_of_data_omap4, },
+ { .compatible = "ti,omap5-dsi", .data = dsi_of_data_omap5, },
{},
};
diff --git a/drivers/video/fbdev/omap2/dss/dss.c b/drivers/video/fbdev/omap2/dss/dss.c
index d55266c0e029..6daeb7ed44c6 100644
--- a/drivers/video/fbdev/omap2/dss/dss.c
+++ b/drivers/video/fbdev/omap2/dss/dss.c
@@ -728,6 +728,13 @@ static const struct dss_features omap54xx_dss_feats __initconst = {
.dpi_select_source = &dss_dpi_select_source_omap5,
};
+static const struct dss_features am43xx_dss_feats __initconst = {
+ .fck_div_max = 0,
+ .dss_fck_multiplier = 0,
+ .parent_clk_name = NULL,
+ .dpi_select_source = &dss_dpi_select_source_omap2_omap3,
+};
+
static int __init dss_init_features(struct platform_device *pdev)
{
const struct dss_features *src;
@@ -764,6 +771,10 @@ static int __init dss_init_features(struct platform_device *pdev)
src = &omap54xx_dss_feats;
break;
+ case OMAPDSS_VER_AM43xx:
+ src = &am43xx_dss_feats;
+ break;
+
default:
return -ENODEV;
}
@@ -784,12 +795,8 @@ static int __init dss_init_ports(struct platform_device *pdev)
return 0;
port = omapdss_of_get_next_port(parent, NULL);
- if (!port) {
-#ifdef CONFIG_OMAP2_DSS_DPI
- dpi_init_port(pdev, parent);
-#endif
+ if (!port)
return 0;
- }
do {
u32 reg;
@@ -813,7 +820,7 @@ static int __init dss_init_ports(struct platform_device *pdev)
return 0;
}
-static void dss_uninit_ports(void)
+static void __exit dss_uninit_ports(void)
{
#ifdef CONFIG_OMAP2_DSS_DPI
dpi_uninit_port();
@@ -946,6 +953,7 @@ static const struct of_device_id dss_of_match[] = {
{ .compatible = "ti,omap2-dss", },
{ .compatible = "ti,omap3-dss", },
{ .compatible = "ti,omap4-dss", },
+ { .compatible = "ti,omap5-dss", },
{},
};
diff --git a/drivers/video/fbdev/omap2/dss/dss.h b/drivers/video/fbdev/omap2/dss/dss.h
index 560078fcb198..8ff22c134c62 100644
--- a/drivers/video/fbdev/omap2/dss/dss.h
+++ b/drivers/video/fbdev/omap2/dss/dss.h
@@ -419,6 +419,9 @@ void venc_uninit_platform_driver(void) __exit;
int hdmi4_init_platform_driver(void) __init;
void hdmi4_uninit_platform_driver(void) __exit;
+int hdmi5_init_platform_driver(void) __init;
+void hdmi5_uninit_platform_driver(void) __exit;
+
/* RFBI */
int rfbi_init_platform_driver(void) __init;
void rfbi_uninit_platform_driver(void) __exit;
diff --git a/drivers/video/fbdev/omap2/dss/dss_features.c b/drivers/video/fbdev/omap2/dss/dss_features.c
index 7f8969191dc6..15088df7bd16 100644
--- a/drivers/video/fbdev/omap2/dss/dss_features.c
+++ b/drivers/video/fbdev/omap2/dss/dss_features.c
@@ -93,6 +93,17 @@ static const struct dss_reg_field omap3_dss_reg_fields[] = {
[FEAT_REG_DSIPLL_REGM_DSI] = { 26, 23 },
};
+static const struct dss_reg_field am43xx_dss_reg_fields[] = {
+ [FEAT_REG_FIRHINC] = { 12, 0 },
+ [FEAT_REG_FIRVINC] = { 28, 16 },
+ [FEAT_REG_FIFOLOWTHRESHOLD] = { 11, 0 },
+ [FEAT_REG_FIFOHIGHTHRESHOLD] = { 27, 16 },
+ [FEAT_REG_FIFOSIZE] = { 10, 0 },
+ [FEAT_REG_HORIZONTALACCU] = { 9, 0 },
+ [FEAT_REG_VERTICALACCU] = { 25, 16 },
+ [FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
+};
+
static const struct dss_reg_field omap4_dss_reg_fields[] = {
[FEAT_REG_FIRHINC] = { 12, 0 },
[FEAT_REG_FIRVINC] = { 28, 16 },
@@ -149,6 +160,11 @@ static const enum omap_display_type omap3630_dss_supported_displays[] = {
OMAP_DISPLAY_TYPE_VENC,
};
+static const enum omap_display_type am43xx_dss_supported_displays[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DISPLAY_TYPE_DPI | OMAP_DISPLAY_TYPE_DBI,
+};
+
static const enum omap_display_type omap4_dss_supported_displays[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DISPLAY_TYPE_DBI | OMAP_DISPLAY_TYPE_DSI,
@@ -200,6 +216,11 @@ static const enum omap_dss_output_id omap3630_dss_supported_outputs[] = {
OMAP_DSS_OUTPUT_VENC,
};
+static const enum omap_dss_output_id am43xx_dss_supported_outputs[] = {
+ /* OMAP_DSS_CHANNEL_LCD */
+ OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI,
+};
+
static const enum omap_dss_output_id omap4_dss_supported_outputs[] = {
/* OMAP_DSS_CHANNEL_LCD */
OMAP_DSS_OUTPUT_DBI | OMAP_DSS_OUTPUT_DSI1,
@@ -444,6 +465,13 @@ static const struct dss_param_range omap3_dss_param_range[] = {
[FEAT_PARAM_LINEWIDTH] = { 1, 1024 },
};
+static const struct dss_param_range am43xx_dss_param_range[] = {
+ [FEAT_PARAM_DSS_FCK] = { 0, 200000000 },
+ [FEAT_PARAM_DSS_PCD] = { 2, 255 },
+ [FEAT_PARAM_DOWNSCALE] = { 1, 4 },
+ [FEAT_PARAM_LINEWIDTH] = { 1, 1024 },
+};
+
static const struct dss_param_range omap4_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 186000000 },
[FEAT_PARAM_DSS_PCD] = { 1, 255 },
@@ -520,6 +548,21 @@ static const enum dss_feat_id am35xx_dss_feat_list[] = {
FEAT_OMAP3_DSI_FIFO_BUG,
};
+static const enum dss_feat_id am43xx_dss_feat_list[] = {
+ FEAT_LCDENABLEPOL,
+ FEAT_LCDENABLESIGNAL,
+ FEAT_PCKFREEENABLE,
+ FEAT_FUNCGATED,
+ FEAT_LINEBUFFERSPLIT,
+ FEAT_ROWREPEATENABLE,
+ FEAT_RESIZECONF,
+ FEAT_CPR,
+ FEAT_PRELOAD,
+ FEAT_FIR_COEF_V,
+ FEAT_ALPHA_FIXED_ZORDER,
+ FEAT_FIFO_MERGE,
+};
+
static const enum dss_feat_id omap3630_dss_feat_list[] = {
FEAT_LCDENABLEPOL,
FEAT_LCDENABLESIGNAL,
@@ -595,6 +638,7 @@ static const enum dss_feat_id omap4_dss_feat_list[] = {
static const enum dss_feat_id omap5_dss_feat_list[] = {
FEAT_MGR_LCD2,
+ FEAT_MGR_LCD3,
FEAT_CORE_CLK_DIV,
FEAT_LCD_CLK_SRC,
FEAT_DSI_DCS_CMD_CONFIG_VC,
@@ -682,6 +726,26 @@ static const struct omap_dss_features am35xx_dss_features = {
.burst_size_unit = 8,
};
+static const struct omap_dss_features am43xx_dss_features = {
+ .reg_fields = am43xx_dss_reg_fields,
+ .num_reg_fields = ARRAY_SIZE(am43xx_dss_reg_fields),
+
+ .features = am43xx_dss_feat_list,
+ .num_features = ARRAY_SIZE(am43xx_dss_feat_list),
+
+ .num_mgrs = 1,
+ .num_ovls = 3,
+ .supported_displays = am43xx_dss_supported_displays,
+ .supported_outputs = am43xx_dss_supported_outputs,
+ .supported_color_modes = omap3_dss_supported_color_modes,
+ .overlay_caps = omap3430_dss_overlay_caps,
+ .clksrc_names = omap2_dss_clk_source_names,
+ .dss_params = am43xx_dss_param_range,
+ .supported_rotation_types = OMAP_DSS_ROT_DMA,
+ .buffer_size_unit = 1,
+ .burst_size_unit = 8,
+};
+
static const struct omap_dss_features omap3630_dss_features = {
.reg_fields = omap3_dss_reg_fields,
.num_reg_fields = ARRAY_SIZE(omap3_dss_reg_fields),
@@ -777,7 +841,7 @@ static const struct omap_dss_features omap5_dss_features = {
.features = omap5_dss_feat_list,
.num_features = ARRAY_SIZE(omap5_dss_feat_list),
- .num_mgrs = 3,
+ .num_mgrs = 4,
.num_ovls = 4,
.supported_displays = omap5_dss_supported_displays,
.supported_outputs = omap5_dss_supported_outputs,
@@ -928,6 +992,10 @@ void dss_features_init(enum omapdss_version version)
omap_current_dss_features = &am35xx_dss_features;
break;
+ case OMAPDSS_VER_AM43xx:
+ omap_current_dss_features = &am43xx_dss_features;
+ break;
+
default:
DSSWARN("Unsupported OMAP version");
break;
diff --git a/drivers/video/fbdev/omap2/dss/hdmi.h b/drivers/video/fbdev/omap2/dss/hdmi.h
index e25681ff5a70..fbee07816337 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi.h
+++ b/drivers/video/fbdev/omap2/dss/hdmi.h
@@ -80,6 +80,7 @@
#define HDMI_TXPHY_DIGITAL_CTRL 0x4
#define HDMI_TXPHY_POWER_CTRL 0x8
#define HDMI_TXPHY_PAD_CFG_CTRL 0xC
+#define HDMI_TXPHY_BIST_CONTROL 0x1C
enum hdmi_pll_pwr {
HDMI_PLLPWRCMD_ALLOFF = 0,
@@ -351,7 +352,8 @@ struct hdmi_pll_data {
struct hdmi_phy_data {
void __iomem *base;
- int irq;
+ u8 lane_function[4];
+ u8 lane_polarity[4];
};
struct hdmi_core_data {
@@ -360,13 +362,13 @@ struct hdmi_core_data {
struct hdmi_core_infoframe_avi avi_cfg;
};
-static inline void hdmi_write_reg(void __iomem *base_addr, const u16 idx,
+static inline void hdmi_write_reg(void __iomem *base_addr, const u32 idx,
u32 val)
{
__raw_writel(val, base_addr + idx);
}
-static inline u32 hdmi_read_reg(void __iomem *base_addr, const u16 idx)
+static inline u32 hdmi_read_reg(void __iomem *base_addr, const u32 idx)
{
return __raw_readl(base_addr + idx);
}
@@ -417,18 +419,19 @@ void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy);
int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll);
/* HDMI PHY funcs */
-int hdmi_phy_enable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp,
- struct hdmi_config *cfg);
-void hdmi_phy_disable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp);
+int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg);
void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s);
int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy);
+int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes);
/* HDMI common funcs */
const struct hdmi_config *hdmi_default_timing(void);
const struct hdmi_config *hdmi_get_timings(int mode, int code);
struct hdmi_cm hdmi_get_code(struct omap_video_timings *timing);
+int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep,
+ struct hdmi_phy_data *phy);
-#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
+#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) || defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts);
int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable);
int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable);
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c b/drivers/video/fbdev/omap2/dss/hdmi4.c
index f5f7944a1fd1..626aad2bef46 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi4.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi4.c
@@ -81,8 +81,40 @@ static void hdmi_runtime_put(void)
WARN_ON(r < 0 && r != -ENOSYS);
}
+static irqreturn_t hdmi_irq_handler(int irq, void *data)
+{
+ struct hdmi_wp_data *wp = data;
+ u32 irqstatus;
+
+ irqstatus = hdmi_wp_get_irqstatus(wp);
+ hdmi_wp_set_irqstatus(wp, irqstatus);
+
+ if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
+ irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
+ /*
+ * If we get both connect and disconnect interrupts at the same
+ * time, turn off the PHY, clear interrupts, and restart, which
+ * raises connect interrupt if a cable is connected, or nothing
+ * if cable is not connected.
+ */
+ hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
+
+ hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
+ HDMI_IRQ_LINK_DISCONNECT);
+
+ hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
+ } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
+ hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
+ } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
+ hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
+ }
+
+ return IRQ_HANDLED;
+}
+
static int hdmi_init_regulator(void)
{
+ int r;
struct regulator *reg;
if (hdmi.vdda_hdmi_dac_reg != NULL)
@@ -96,6 +128,15 @@ static int hdmi_init_regulator(void)
return PTR_ERR(reg);
}
+ if (regulator_can_change_voltage(reg)) {
+ r = regulator_set_voltage(reg, 1800000, 1800000);
+ if (r) {
+ devm_regulator_put(reg);
+ DSSWARN("can't set the regulator voltage\n");
+ return r;
+ }
+ }
+
hdmi.vdda_hdmi_dac_reg = reg;
return 0;
@@ -140,11 +181,16 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
struct omap_video_timings *p;
struct omap_overlay_manager *mgr = hdmi.output.manager;
unsigned long phy;
+ struct hdmi_wp_data *wp = &hdmi.wp;
r = hdmi_power_on_core(dssdev);
if (r)
return r;
+ /* disable and clear irqs */
+ hdmi_wp_clear_irqenable(wp, 0xffffffff);
+ hdmi_wp_set_irqstatus(wp, 0xffffffff);
+
p = &hdmi.cfg.timings;
DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
@@ -161,12 +207,16 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
goto err_pll_enable;
}
- r = hdmi_phy_enable(&hdmi.phy, &hdmi.wp, &hdmi.cfg);
+ r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg);
if (r) {
- DSSDBG("Failed to start PHY\n");
- goto err_phy_enable;
+ DSSDBG("Failed to configure PHY\n");
+ goto err_phy_cfg;
}
+ r = hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
+ if (r)
+ goto err_phy_pwr;
+
hdmi4_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);
/* bypass TV gamma table */
@@ -183,13 +233,17 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
if (r)
goto err_mgr_enable;
+ hdmi_wp_set_irqenable(wp,
+ HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
+
return 0;
err_mgr_enable:
hdmi_wp_video_stop(&hdmi.wp);
err_vid_enable:
- hdmi_phy_disable(&hdmi.phy, &hdmi.wp);
-err_phy_enable:
+err_phy_cfg:
+ hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
+err_phy_pwr:
hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
err_pll_enable:
hdmi_power_off_core(dssdev);
@@ -200,10 +254,14 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev)
{
struct omap_overlay_manager *mgr = hdmi.output.manager;
+ hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
+
dss_mgr_disable(mgr);
hdmi_wp_video_stop(&hdmi.wp);
- hdmi_phy_disable(&hdmi.phy, &hdmi.wp);
+
+ hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
+
hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
hdmi_power_off_core(dssdev);
@@ -600,15 +658,44 @@ static void __exit hdmi_uninit_output(struct platform_device *pdev)
omapdss_unregister_output(out);
}
+static int hdmi_probe_of(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct device_node *ep;
+ int r;
+
+ ep = omapdss_of_get_first_endpoint(node);
+ if (!ep)
+ return 0;
+
+ r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy);
+ if (r)
+ goto err;
+
+ of_node_put(ep);
+ return 0;
+
+err:
+ of_node_put(ep);
+ return r;
+}
+
/* HDMI HW IP initialisation */
static int omapdss_hdmihw_probe(struct platform_device *pdev)
{
int r;
+ int irq;
hdmi.pdev = pdev;
mutex_init(&hdmi.lock);
+ if (pdev->dev.of_node) {
+ r = hdmi_probe_of(pdev);
+ if (r)
+ return r;
+ }
+
r = hdmi_wp_init(pdev, &hdmi.wp);
if (r)
return r;
@@ -631,6 +718,20 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
return r;
}
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ DSSERR("platform_get_irq failed\n");
+ return -ENODEV;
+ }
+
+ r = devm_request_threaded_irq(&pdev->dev, irq,
+ NULL, hdmi_irq_handler,
+ IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
+ if (r) {
+ DSSERR("HDMI IRQ request failed\n");
+ return r;
+ }
+
pm_runtime_enable(&pdev->dev);
hdmi_init_output(pdev);
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.c b/drivers/video/fbdev/omap2/dss/hdmi4_core.c
index 2eb04dcf807c..8bde7b7e95ff 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi4_core.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi4_core.c
@@ -998,38 +998,20 @@ int hdmi4_audio_get_dma_port(u32 *offset, u32 *size)
#endif
-#define CORE_OFFSET 0x400
-#define CORE_SIZE 0xc00
-
int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core)
{
struct resource *res;
- struct resource temp_res;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
if (!res) {
- DSSDBG("can't get CORE mem resource by name\n");
- /*
- * if hwmod/DT doesn't have the memory resource information
- * split into HDMI sub blocks by name, we try again by getting
- * the platform's first resource. this code will be removed when
- * the driver can get the mem resources by name
- */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- DSSERR("can't get CORE mem resource\n");
- return -EINVAL;
- }
-
- temp_res.start = res->start + CORE_OFFSET;
- temp_res.end = temp_res.start + CORE_SIZE - 1;
- res = &temp_res;
+ DSSERR("can't get CORE mem resource\n");
+ return -EINVAL;
}
- core->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!core->base) {
+ core->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(core->base)) {
DSSERR("can't ioremap CORE\n");
- return -ENOMEM;
+ return PTR_ERR(core->base);
}
return 0;
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5.c b/drivers/video/fbdev/omap2/dss/hdmi5.c
new file mode 100644
index 000000000000..c468b9e1f295
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/hdmi5.c
@@ -0,0 +1,829 @@
+/*
+ * HDMI driver for OMAP5
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated
+ *
+ * Authors:
+ * Yong Zhi
+ * Mythri pk
+ * Archit Taneja <archit@ti.com>
+ * Tomi Valkeinen <tomi.valkeinen@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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DSS_SUBSYS_NAME "HDMI"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/clk.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
+#include <video/omapdss.h>
+
+#include "hdmi5_core.h"
+#include "dss.h"
+#include "dss_features.h"
+
+static struct {
+ struct mutex lock;
+ struct platform_device *pdev;
+
+ struct hdmi_wp_data wp;
+ struct hdmi_pll_data pll;
+ struct hdmi_phy_data phy;
+ struct hdmi_core_data core;
+
+ struct hdmi_config cfg;
+
+ struct clk *sys_clk;
+ struct regulator *vdda_reg;
+
+ bool core_enabled;
+
+ struct omap_dss_device output;
+} hdmi;
+
+static int hdmi_runtime_get(void)
+{
+ int r;
+
+ DSSDBG("hdmi_runtime_get\n");
+
+ r = pm_runtime_get_sync(&hdmi.pdev->dev);
+ WARN_ON(r < 0);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static void hdmi_runtime_put(void)
+{
+ int r;
+
+ DSSDBG("hdmi_runtime_put\n");
+
+ r = pm_runtime_put_sync(&hdmi.pdev->dev);
+ WARN_ON(r < 0 && r != -ENOSYS);
+}
+
+static irqreturn_t hdmi_irq_handler(int irq, void *data)
+{
+ struct hdmi_wp_data *wp = data;
+ u32 irqstatus;
+
+ irqstatus = hdmi_wp_get_irqstatus(wp);
+ hdmi_wp_set_irqstatus(wp, irqstatus);
+
+ if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
+ irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
+ u32 v;
+ /*
+ * If we get both connect and disconnect interrupts at the same
+ * time, turn off the PHY, clear interrupts, and restart, which
+ * raises connect interrupt if a cable is connected, or nothing
+ * if cable is not connected.
+ */
+
+ hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
+
+ /*
+ * We always get bogus CONNECT & DISCONNECT interrupts when
+ * setting the PHY to LDOON. To ignore those, we force the RXDET
+ * line to 0 until the PHY power state has been changed.
+ */
+ v = hdmi_read_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL);
+ v = FLD_MOD(v, 1, 15, 15); /* FORCE_RXDET_HIGH */
+ v = FLD_MOD(v, 0, 14, 7); /* RXDET_LINE */
+ hdmi_write_reg(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, v);
+
+ hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
+ HDMI_IRQ_LINK_DISCONNECT);
+
+ hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
+
+ REG_FLD_MOD(hdmi.phy.base, HDMI_TXPHY_PAD_CFG_CTRL, 0, 15, 15);
+
+ } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
+ hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
+ } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
+ hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int hdmi_init_regulator(void)
+{
+ int r;
+ struct regulator *reg;
+
+ if (hdmi.vdda_reg != NULL)
+ return 0;
+
+ reg = devm_regulator_get(&hdmi.pdev->dev, "vdda");
+ if (IS_ERR(reg)) {
+ DSSERR("can't get VDDA regulator\n");
+ return PTR_ERR(reg);
+ }
+
+ if (regulator_can_change_voltage(reg)) {
+ r = regulator_set_voltage(reg, 1800000, 1800000);
+ if (r) {
+ devm_regulator_put(reg);
+ DSSWARN("can't set the regulator voltage\n");
+ return r;
+ }
+ }
+
+ hdmi.vdda_reg = reg;
+
+ return 0;
+}
+
+static int hdmi_power_on_core(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ r = regulator_enable(hdmi.vdda_reg);
+ if (r)
+ return r;
+
+ r = hdmi_runtime_get();
+ if (r)
+ goto err_runtime_get;
+
+ /* Make selection of HDMI in DSS */
+ dss_select_hdmi_venc_clk_source(DSS_HDMI_M_PCLK);
+
+ hdmi.core_enabled = true;
+
+ return 0;
+
+err_runtime_get:
+ regulator_disable(hdmi.vdda_reg);
+
+ return r;
+}
+
+static void hdmi_power_off_core(struct omap_dss_device *dssdev)
+{
+ hdmi.core_enabled = false;
+
+ hdmi_runtime_put();
+ regulator_disable(hdmi.vdda_reg);
+}
+
+static int hdmi_power_on_full(struct omap_dss_device *dssdev)
+{
+ int r;
+ struct omap_video_timings *p;
+ struct omap_overlay_manager *mgr = hdmi.output.manager;
+ unsigned long phy;
+
+ r = hdmi_power_on_core(dssdev);
+ if (r)
+ return r;
+
+ p = &hdmi.cfg.timings;
+
+ DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
+
+ /* the functions below use kHz pixel clock. TODO: change to Hz */
+ phy = p->pixelclock / 1000;
+
+ hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy);
+
+ /* disable and clear irqs */
+ hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
+ hdmi_wp_set_irqstatus(&hdmi.wp,
+ hdmi_wp_get_irqstatus(&hdmi.wp));
+
+ /* config the PLL and PHY hdmi_set_pll_pwrfirst */
+ r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp);
+ if (r) {
+ DSSDBG("Failed to lock PLL\n");
+ goto err_pll_enable;
+ }
+
+ r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg);
+ if (r) {
+ DSSDBG("Failed to start PHY\n");
+ goto err_phy_cfg;
+ }
+
+ r = hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_LDOON);
+ if (r)
+ goto err_phy_pwr;
+
+ hdmi5_configure(&hdmi.core, &hdmi.wp, &hdmi.cfg);
+
+ /* bypass TV gamma table */
+ dispc_enable_gamma_table(0);
+
+ /* tv size */
+ dss_mgr_set_timings(mgr, p);
+
+ r = hdmi_wp_video_start(&hdmi.wp);
+ if (r)
+ goto err_vid_enable;
+
+ r = dss_mgr_enable(mgr);
+ if (r)
+ goto err_mgr_enable;
+
+ hdmi_wp_set_irqenable(&hdmi.wp,
+ HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
+
+ return 0;
+
+err_mgr_enable:
+ hdmi_wp_video_stop(&hdmi.wp);
+err_vid_enable:
+ hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
+err_phy_pwr:
+err_phy_cfg:
+ hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
+err_pll_enable:
+ hdmi_power_off_core(dssdev);
+ return -EIO;
+}
+
+static void hdmi_power_off_full(struct omap_dss_device *dssdev)
+{
+ struct omap_overlay_manager *mgr = hdmi.output.manager;
+
+ hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
+
+ dss_mgr_disable(mgr);
+
+ hdmi_wp_video_stop(&hdmi.wp);
+
+ hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
+
+ hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
+
+ hdmi_power_off_core(dssdev);
+}
+
+static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct omap_dss_device *out = &hdmi.output;
+
+ if (!dispc_mgr_timings_ok(out->dispc_channel, timings))
+ return -EINVAL;
+
+ return 0;
+}
+
+static void hdmi_display_set_timing(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct hdmi_cm cm;
+ const struct hdmi_config *t;
+
+ mutex_lock(&hdmi.lock);
+
+ cm = hdmi_get_code(timings);
+ hdmi.cfg.cm = cm;
+
+ t = hdmi_get_timings(cm.mode, cm.code);
+ if (t != NULL) {
+ hdmi.cfg = *t;
+
+ dispc_set_tv_pclk(t->timings.pixelclock);
+ } else {
+ hdmi.cfg.timings = *timings;
+ hdmi.cfg.cm.code = 0;
+ hdmi.cfg.cm.mode = HDMI_DVI;
+
+ dispc_set_tv_pclk(timings->pixelclock);
+ }
+
+ DSSDBG("using mode: %s, code %d\n", hdmi.cfg.cm.mode == HDMI_DVI ?
+ "DVI" : "HDMI", hdmi.cfg.cm.code);
+
+ mutex_unlock(&hdmi.lock);
+}
+
+static void hdmi_display_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ const struct hdmi_config *cfg;
+ struct hdmi_cm cm = hdmi.cfg.cm;
+
+ cfg = hdmi_get_timings(cm.mode, cm.code);
+ if (cfg == NULL)
+ cfg = hdmi_default_timing();
+
+ memcpy(timings, &cfg->timings, sizeof(cfg->timings));
+}
+
+static void hdmi_dump_regs(struct seq_file *s)
+{
+ mutex_lock(&hdmi.lock);
+
+ if (hdmi_runtime_get()) {
+ mutex_unlock(&hdmi.lock);
+ return;
+ }
+
+ hdmi_wp_dump(&hdmi.wp, s);
+ hdmi_pll_dump(&hdmi.pll, s);
+ hdmi_phy_dump(&hdmi.phy, s);
+ hdmi5_core_dump(&hdmi.core, s);
+
+ hdmi_runtime_put();
+ mutex_unlock(&hdmi.lock);
+}
+
+static int read_edid(u8 *buf, int len)
+{
+ int r;
+ int idlemode;
+
+ mutex_lock(&hdmi.lock);
+
+ r = hdmi_runtime_get();
+ BUG_ON(r);
+
+ idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
+ /* No-idle mode */
+ REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
+
+ r = hdmi5_read_edid(&hdmi.core, buf, len);
+
+ REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, idlemode, 3, 2);
+
+ hdmi_runtime_put();
+ mutex_unlock(&hdmi.lock);
+
+ return r;
+}
+
+static int hdmi_display_enable(struct omap_dss_device *dssdev)
+{
+ struct omap_dss_device *out = &hdmi.output;
+ int r = 0;
+
+ DSSDBG("ENTER hdmi_display_enable\n");
+
+ mutex_lock(&hdmi.lock);
+
+ if (out == NULL || out->manager == NULL) {
+ DSSERR("failed to enable display: no output/manager\n");
+ r = -ENODEV;
+ goto err0;
+ }
+
+ r = hdmi_power_on_full(dssdev);
+ if (r) {
+ DSSERR("failed to power on device\n");
+ goto err0;
+ }
+
+ mutex_unlock(&hdmi.lock);
+ return 0;
+
+err0:
+ mutex_unlock(&hdmi.lock);
+ return r;
+}
+
+static void hdmi_display_disable(struct omap_dss_device *dssdev)
+{
+ DSSDBG("Enter hdmi_display_disable\n");
+
+ mutex_lock(&hdmi.lock);
+
+ hdmi_power_off_full(dssdev);
+
+ mutex_unlock(&hdmi.lock);
+}
+
+static int hdmi_core_enable(struct omap_dss_device *dssdev)
+{
+ int r = 0;
+
+ DSSDBG("ENTER omapdss_hdmi_core_enable\n");
+
+ mutex_lock(&hdmi.lock);
+
+ r = hdmi_power_on_core(dssdev);
+ if (r) {
+ DSSERR("failed to power on device\n");
+ goto err0;
+ }
+
+ mutex_unlock(&hdmi.lock);
+ return 0;
+
+err0:
+ mutex_unlock(&hdmi.lock);
+ return r;
+}
+
+static void hdmi_core_disable(struct omap_dss_device *dssdev)
+{
+ DSSDBG("Enter omapdss_hdmi_core_disable\n");
+
+ mutex_lock(&hdmi.lock);
+
+ hdmi_power_off_core(dssdev);
+
+ mutex_unlock(&hdmi.lock);
+}
+
+static int hdmi_get_clocks(struct platform_device *pdev)
+{
+ struct clk *clk;
+
+ clk = devm_clk_get(&pdev->dev, "sys_clk");
+ if (IS_ERR(clk)) {
+ DSSERR("can't get sys_clk\n");
+ return PTR_ERR(clk);
+ }
+
+ hdmi.sys_clk = clk;
+
+ return 0;
+}
+
+static int hdmi_connect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct omap_overlay_manager *mgr;
+ int r;
+
+ r = hdmi_init_regulator();
+ if (r)
+ return r;
+
+ mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
+ if (!mgr)
+ return -ENODEV;
+
+ r = dss_mgr_connect(mgr, dssdev);
+ if (r)
+ return r;
+
+ r = omapdss_output_set_device(dssdev, dst);
+ if (r) {
+ DSSERR("failed to connect output to new device: %s\n",
+ dst->name);
+ dss_mgr_disconnect(mgr, dssdev);
+ return r;
+ }
+
+ return 0;
+}
+
+static void hdmi_disconnect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ WARN_ON(dst != dssdev->dst);
+
+ if (dst != dssdev->dst)
+ return;
+
+ omapdss_output_unset_device(dssdev);
+
+ if (dssdev->manager)
+ dss_mgr_disconnect(dssdev->manager, dssdev);
+}
+
+static int hdmi_read_edid(struct omap_dss_device *dssdev,
+ u8 *edid, int len)
+{
+ bool need_enable;
+ int r;
+
+ need_enable = hdmi.core_enabled == false;
+
+ if (need_enable) {
+ r = hdmi_core_enable(dssdev);
+ if (r)
+ return r;
+ }
+
+ r = read_edid(edid, len);
+
+ if (need_enable)
+ hdmi_core_disable(dssdev);
+
+ return r;
+}
+
+#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
+static int hdmi_audio_enable(struct omap_dss_device *dssdev)
+{
+ int r;
+
+ mutex_lock(&hdmi.lock);
+
+ if (!hdmi_mode_has_audio(hdmi.cfg.cm.mode)) {
+ r = -EPERM;
+ goto err;
+ }
+
+ r = hdmi_wp_audio_enable(&hdmi.wp, true);
+ if (r)
+ goto err;
+
+ mutex_unlock(&hdmi.lock);
+ return 0;
+
+err:
+ mutex_unlock(&hdmi.lock);
+ return r;
+}
+
+static void hdmi_audio_disable(struct omap_dss_device *dssdev)
+{
+ hdmi_wp_audio_enable(&hdmi.wp, false);
+}
+
+static int hdmi_audio_start(struct omap_dss_device *dssdev)
+{
+ return hdmi_wp_audio_core_req_enable(&hdmi.wp, true);
+}
+
+static void hdmi_audio_stop(struct omap_dss_device *dssdev)
+{
+ hdmi_wp_audio_core_req_enable(&hdmi.wp, false);
+}
+
+static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
+{
+ bool r;
+
+ mutex_lock(&hdmi.lock);
+
+ r = hdmi_mode_has_audio(hdmi.cfg.cm.mode);
+
+ mutex_unlock(&hdmi.lock);
+ return r;
+}
+
+static int hdmi_audio_config(struct omap_dss_device *dssdev,
+ struct omap_dss_audio *audio)
+{
+ int r;
+ u32 pclk = hdmi.cfg.timings.pixelclock;
+
+ mutex_lock(&hdmi.lock);
+
+ if (!hdmi_mode_has_audio(hdmi.cfg.cm.mode)) {
+ r = -EPERM;
+ goto err;
+ }
+
+ r = hdmi5_audio_config(&hdmi.core, &hdmi.wp, audio, pclk);
+ if (r)
+ goto err;
+
+ mutex_unlock(&hdmi.lock);
+ return 0;
+
+err:
+ mutex_unlock(&hdmi.lock);
+ return r;
+}
+#else
+static int hdmi_audio_enable(struct omap_dss_device *dssdev)
+{
+ return -EPERM;
+}
+
+static void hdmi_audio_disable(struct omap_dss_device *dssdev)
+{
+}
+
+static int hdmi_audio_start(struct omap_dss_device *dssdev)
+{
+ return -EPERM;
+}
+
+static void hdmi_audio_stop(struct omap_dss_device *dssdev)
+{
+}
+
+static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
+{
+ return false;
+}
+
+static int hdmi_audio_config(struct omap_dss_device *dssdev,
+ struct omap_dss_audio *audio)
+{
+ return -EPERM;
+}
+#endif
+
+static const struct omapdss_hdmi_ops hdmi_ops = {
+ .connect = hdmi_connect,
+ .disconnect = hdmi_disconnect,
+
+ .enable = hdmi_display_enable,
+ .disable = hdmi_display_disable,
+
+ .check_timings = hdmi_display_check_timing,
+ .set_timings = hdmi_display_set_timing,
+ .get_timings = hdmi_display_get_timings,
+
+ .read_edid = hdmi_read_edid,
+
+ .audio_enable = hdmi_audio_enable,
+ .audio_disable = hdmi_audio_disable,
+ .audio_start = hdmi_audio_start,
+ .audio_stop = hdmi_audio_stop,
+ .audio_supported = hdmi_audio_supported,
+ .audio_config = hdmi_audio_config,
+};
+
+static void hdmi_init_output(struct platform_device *pdev)
+{
+ struct omap_dss_device *out = &hdmi.output;
+
+ out->dev = &pdev->dev;
+ out->id = OMAP_DSS_OUTPUT_HDMI;
+ out->output_type = OMAP_DISPLAY_TYPE_HDMI;
+ out->name = "hdmi.0";
+ out->dispc_channel = OMAP_DSS_CHANNEL_DIGIT;
+ out->ops.hdmi = &hdmi_ops;
+ out->owner = THIS_MODULE;
+
+ omapdss_register_output(out);
+}
+
+static void __exit hdmi_uninit_output(struct platform_device *pdev)
+{
+ struct omap_dss_device *out = &hdmi.output;
+
+ omapdss_unregister_output(out);
+}
+
+static int hdmi_probe_of(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct device_node *ep;
+ int r;
+
+ ep = omapdss_of_get_first_endpoint(node);
+ if (!ep)
+ return 0;
+
+ r = hdmi_parse_lanes_of(pdev, ep, &hdmi.phy);
+ if (r)
+ goto err;
+
+ of_node_put(ep);
+ return 0;
+
+err:
+ of_node_put(ep);
+ return r;
+}
+
+/* HDMI HW IP initialisation */
+static int omapdss_hdmihw_probe(struct platform_device *pdev)
+{
+ int r;
+ int irq;
+
+ hdmi.pdev = pdev;
+
+ mutex_init(&hdmi.lock);
+
+ if (pdev->dev.of_node) {
+ r = hdmi_probe_of(pdev);
+ if (r)
+ return r;
+ }
+
+ r = hdmi_wp_init(pdev, &hdmi.wp);
+ if (r)
+ return r;
+
+ r = hdmi_pll_init(pdev, &hdmi.pll);
+ if (r)
+ return r;
+
+ r = hdmi_phy_init(pdev, &hdmi.phy);
+ if (r)
+ return r;
+
+ r = hdmi5_core_init(pdev, &hdmi.core);
+ if (r)
+ return r;
+
+ r = hdmi_get_clocks(pdev);
+ if (r) {
+ DSSERR("can't get clocks\n");
+ return r;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ DSSERR("platform_get_irq failed\n");
+ return -ENODEV;
+ }
+
+ r = devm_request_threaded_irq(&pdev->dev, irq,
+ NULL, hdmi_irq_handler,
+ IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
+ if (r) {
+ DSSERR("HDMI IRQ request failed\n");
+ return r;
+ }
+
+ pm_runtime_enable(&pdev->dev);
+
+ hdmi_init_output(pdev);
+
+ dss_debugfs_create_file("hdmi", hdmi_dump_regs);
+
+ return 0;
+}
+
+static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
+{
+ hdmi_uninit_output(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static int hdmi_runtime_suspend(struct device *dev)
+{
+ clk_disable_unprepare(hdmi.sys_clk);
+
+ dispc_runtime_put();
+
+ return 0;
+}
+
+static int hdmi_runtime_resume(struct device *dev)
+{
+ int r;
+
+ r = dispc_runtime_get();
+ if (r < 0)
+ return r;
+
+ clk_prepare_enable(hdmi.sys_clk);
+
+ return 0;
+}
+
+static const struct dev_pm_ops hdmi_pm_ops = {
+ .runtime_suspend = hdmi_runtime_suspend,
+ .runtime_resume = hdmi_runtime_resume,
+};
+
+static const struct of_device_id hdmi_of_match[] = {
+ { .compatible = "ti,omap5-hdmi", },
+ {},
+};
+
+static struct platform_driver omapdss_hdmihw_driver = {
+ .probe = omapdss_hdmihw_probe,
+ .remove = __exit_p(omapdss_hdmihw_remove),
+ .driver = {
+ .name = "omapdss_hdmi5",
+ .owner = THIS_MODULE,
+ .pm = &hdmi_pm_ops,
+ .of_match_table = hdmi_of_match,
+ },
+};
+
+int __init hdmi5_init_platform_driver(void)
+{
+ return platform_driver_register(&omapdss_hdmihw_driver);
+}
+
+void __exit hdmi5_uninit_platform_driver(void)
+{
+ platform_driver_unregister(&omapdss_hdmihw_driver);
+}
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5_core.c b/drivers/video/fbdev/omap2/dss/hdmi5_core.c
new file mode 100644
index 000000000000..7528c7a42aa5
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/hdmi5_core.c
@@ -0,0 +1,922 @@
+/*
+ * OMAP5 HDMI CORE IP driver library
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated
+ *
+ * Authors:
+ * Yong Zhi
+ * Mythri pk
+ * Archit Taneja <archit@ti.com>
+ * Tomi Valkeinen <tomi.valkeinen@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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/seq_file.h>
+#include <drm/drm_edid.h>
+#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
+#include <sound/asound.h>
+#include <sound/asoundef.h>
+#endif
+
+#include "hdmi5_core.h"
+
+/* only 24 bit color depth used for now */
+static const struct csc_table csc_table_deepcolor[] = {
+ /* HDMI_DEEP_COLOR_24BIT */
+ [0] = { 7036, 0, 0, 32, 0, 7036, 0, 32, 0, 0, 7036, 32, },
+ /* HDMI_DEEP_COLOR_30BIT */
+ [1] = { 7015, 0, 0, 128, 0, 7015, 0, 128, 0, 0, 7015, 128, },
+ /* HDMI_DEEP_COLOR_36BIT */
+ [2] = { 7010, 0, 0, 512, 0, 7010, 0, 512, 0, 0, 7010, 512, },
+ /* FULL RANGE */
+ [3] = { 8192, 0, 0, 0, 0, 8192, 0, 0, 0, 0, 8192, 0, },
+};
+
+static void hdmi_core_ddc_init(struct hdmi_core_data *core)
+{
+ void __iomem *base = core->base;
+ const unsigned long long iclk = 266000000; /* DSS L3 ICLK */
+ const unsigned ss_scl_high = 4000; /* ns */
+ const unsigned ss_scl_low = 4700; /* ns */
+ const unsigned fs_scl_high = 600; /* ns */
+ const unsigned fs_scl_low = 1300; /* ns */
+ const unsigned sda_hold = 300; /* ns */
+ const unsigned sfr_div = 10;
+ unsigned long long sfr;
+ unsigned v;
+
+ sfr = iclk / sfr_div; /* SFR_DIV */
+ sfr /= 1000; /* SFR clock in kHz */
+
+ /* Reset */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SOFTRSTZ, 0, 0, 0);
+ if (hdmi_wait_for_bit_change(base, HDMI_CORE_I2CM_SOFTRSTZ,
+ 0, 0, 1) != 1)
+ DSSERR("HDMI I2CM reset failed\n");
+
+ /* Standard (0) or Fast (1) Mode */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_DIV, 0, 3, 3);
+
+ /* Standard Mode SCL High counter */
+ v = DIV_ROUND_UP_ULL(ss_scl_high * sfr, 1000000);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_HCNT_1_ADDR,
+ (v >> 8) & 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_HCNT_0_ADDR,
+ v & 0xff, 7, 0);
+
+ /* Standard Mode SCL Low counter */
+ v = DIV_ROUND_UP_ULL(ss_scl_low * sfr, 1000000);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_LCNT_1_ADDR,
+ (v >> 8) & 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SS_SCL_LCNT_0_ADDR,
+ v & 0xff, 7, 0);
+
+ /* Fast Mode SCL High Counter */
+ v = DIV_ROUND_UP_ULL(fs_scl_high * sfr, 1000000);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_HCNT_1_ADDR,
+ (v >> 8) & 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_HCNT_0_ADDR,
+ v & 0xff, 7, 0);
+
+ /* Fast Mode SCL Low Counter */
+ v = DIV_ROUND_UP_ULL(fs_scl_low * sfr, 1000000);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_LCNT_1_ADDR,
+ (v >> 8) & 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_FS_SCL_LCNT_0_ADDR,
+ v & 0xff, 7, 0);
+
+ /* SDA Hold Time */
+ v = DIV_ROUND_UP_ULL(sda_hold * sfr, 1000000);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SDA_HOLD_ADDR, v & 0xff, 7, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SLAVE, 0x50, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SEGADDR, 0x30, 6, 0);
+
+ /* NACK_POL to high */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 7, 7);
+
+ /* NACK_MASK to unmasked */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x0, 6, 6);
+
+ /* ARBITRATION_POL to high */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 3, 3);
+
+ /* ARBITRATION_MASK to unmasked */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x0, 2, 2);
+
+ /* DONE_POL to high */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x1, 3, 3);
+
+ /* DONE_MASK to unmasked */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x0, 2, 2);
+}
+
+static void hdmi_core_ddc_uninit(struct hdmi_core_data *core)
+{
+ void __iomem *base = core->base;
+
+ /* Mask I2C interrupts */
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 6, 6);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 2, 2);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x1, 2, 2);
+}
+
+static int hdmi_core_ddc_edid(struct hdmi_core_data *core, u8 *pedid, u8 ext)
+{
+ void __iomem *base = core->base;
+ u8 cur_addr;
+ char checksum = 0;
+ const int retries = 1000;
+ u8 seg_ptr = ext / 2;
+ u8 edidbase = ((ext % 2) * 0x80);
+
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_SEGPTR, seg_ptr, 7, 0);
+
+ /*
+ * TODO: We use polling here, although we probably should use proper
+ * interrupts.
+ */
+ for (cur_addr = 0; cur_addr < 128; ++cur_addr) {
+ int i;
+
+ /* clear ERROR and DONE */
+ REG_FLD_MOD(base, HDMI_CORE_IH_I2CM_STAT0, 0x3, 1, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_ADDRESS,
+ edidbase + cur_addr, 7, 0);
+
+ if (seg_ptr)
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_OPERATION, 1, 1, 1);
+ else
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_OPERATION, 1, 0, 0);
+
+ for (i = 0; i < retries; ++i) {
+ u32 stat;
+
+ stat = REG_GET(base, HDMI_CORE_IH_I2CM_STAT0, 1, 0);
+
+ /* I2CM_ERROR */
+ if (stat & 1) {
+ DSSERR("HDMI I2C Master Error\n");
+ return -EIO;
+ }
+
+ /* I2CM_DONE */
+ if (stat & (1 << 1))
+ break;
+
+ usleep_range(250, 1000);
+ }
+
+ if (i == retries) {
+ DSSERR("HDMI I2C timeout reading EDID\n");
+ return -EIO;
+ }
+
+ pedid[cur_addr] = REG_GET(base, HDMI_CORE_I2CM_DATAI, 7, 0);
+ checksum += pedid[cur_addr];
+ }
+
+ return 0;
+
+}
+
+int hdmi5_read_edid(struct hdmi_core_data *core, u8 *edid, int len)
+{
+ int r, n, i;
+ int max_ext_blocks = (len / 128) - 1;
+
+ if (len < 128)
+ return -EINVAL;
+
+ hdmi_core_ddc_init(core);
+
+ r = hdmi_core_ddc_edid(core, edid, 0);
+ if (r)
+ goto out;
+
+ n = edid[0x7e];
+
+ if (n > max_ext_blocks)
+ n = max_ext_blocks;
+
+ for (i = 1; i <= n; i++) {
+ r = hdmi_core_ddc_edid(core, edid + i * EDID_LENGTH, i);
+ if (r)
+ goto out;
+ }
+
+out:
+ hdmi_core_ddc_uninit(core);
+
+ return r ? r : len;
+}
+
+void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s)
+{
+
+#define DUMPCORE(r) seq_printf(s, "%-35s %08x\n", #r,\
+ hdmi_read_reg(core->base, r))
+
+ DUMPCORE(HDMI_CORE_FC_INVIDCONF);
+ DUMPCORE(HDMI_CORE_FC_INHACTIV0);
+ DUMPCORE(HDMI_CORE_FC_INHACTIV1);
+ DUMPCORE(HDMI_CORE_FC_INHBLANK0);
+ DUMPCORE(HDMI_CORE_FC_INHBLANK1);
+ DUMPCORE(HDMI_CORE_FC_INVACTIV0);
+ DUMPCORE(HDMI_CORE_FC_INVACTIV1);
+ DUMPCORE(HDMI_CORE_FC_INVBLANK);
+ DUMPCORE(HDMI_CORE_FC_HSYNCINDELAY0);
+ DUMPCORE(HDMI_CORE_FC_HSYNCINDELAY1);
+ DUMPCORE(HDMI_CORE_FC_HSYNCINWIDTH0);
+ DUMPCORE(HDMI_CORE_FC_HSYNCINWIDTH1);
+ DUMPCORE(HDMI_CORE_FC_VSYNCINDELAY);
+ DUMPCORE(HDMI_CORE_FC_VSYNCINWIDTH);
+ DUMPCORE(HDMI_CORE_FC_CTRLDUR);
+ DUMPCORE(HDMI_CORE_FC_EXCTRLDUR);
+ DUMPCORE(HDMI_CORE_FC_EXCTRLSPAC);
+ DUMPCORE(HDMI_CORE_FC_CH0PREAM);
+ DUMPCORE(HDMI_CORE_FC_CH1PREAM);
+ DUMPCORE(HDMI_CORE_FC_CH2PREAM);
+ DUMPCORE(HDMI_CORE_FC_AVICONF0);
+ DUMPCORE(HDMI_CORE_FC_AVICONF1);
+ DUMPCORE(HDMI_CORE_FC_AVICONF2);
+ DUMPCORE(HDMI_CORE_FC_AVIVID);
+ DUMPCORE(HDMI_CORE_FC_PRCONF);
+
+ DUMPCORE(HDMI_CORE_MC_CLKDIS);
+ DUMPCORE(HDMI_CORE_MC_SWRSTZREQ);
+ DUMPCORE(HDMI_CORE_MC_FLOWCTRL);
+ DUMPCORE(HDMI_CORE_MC_PHYRSTZ);
+ DUMPCORE(HDMI_CORE_MC_LOCKONCLOCK);
+
+ DUMPCORE(HDMI_CORE_I2CM_SLAVE);
+ DUMPCORE(HDMI_CORE_I2CM_ADDRESS);
+ DUMPCORE(HDMI_CORE_I2CM_DATAO);
+ DUMPCORE(HDMI_CORE_I2CM_DATAI);
+ DUMPCORE(HDMI_CORE_I2CM_OPERATION);
+ DUMPCORE(HDMI_CORE_I2CM_INT);
+ DUMPCORE(HDMI_CORE_I2CM_CTLINT);
+ DUMPCORE(HDMI_CORE_I2CM_DIV);
+ DUMPCORE(HDMI_CORE_I2CM_SEGADDR);
+ DUMPCORE(HDMI_CORE_I2CM_SOFTRSTZ);
+ DUMPCORE(HDMI_CORE_I2CM_SEGPTR);
+ DUMPCORE(HDMI_CORE_I2CM_SS_SCL_HCNT_1_ADDR);
+ DUMPCORE(HDMI_CORE_I2CM_SS_SCL_HCNT_0_ADDR);
+ DUMPCORE(HDMI_CORE_I2CM_SS_SCL_LCNT_1_ADDR);
+ DUMPCORE(HDMI_CORE_I2CM_SS_SCL_LCNT_0_ADDR);
+ DUMPCORE(HDMI_CORE_I2CM_FS_SCL_HCNT_1_ADDR);
+ DUMPCORE(HDMI_CORE_I2CM_FS_SCL_HCNT_0_ADDR);
+ DUMPCORE(HDMI_CORE_I2CM_FS_SCL_LCNT_1_ADDR);
+ DUMPCORE(HDMI_CORE_I2CM_FS_SCL_LCNT_0_ADDR);
+ DUMPCORE(HDMI_CORE_I2CM_SDA_HOLD_ADDR);
+}
+
+static void hdmi_core_init(struct hdmi_core_vid_config *video_cfg,
+ struct hdmi_core_infoframe_avi *avi_cfg,
+ struct hdmi_config *cfg)
+{
+ DSSDBG("hdmi_core_init\n");
+
+ /* video core */
+ video_cfg->data_enable_pol = 1; /* It is always 1*/
+ video_cfg->v_fc_config.timings.hsync_level = cfg->timings.hsync_level;
+ video_cfg->v_fc_config.timings.x_res = cfg->timings.x_res;
+ video_cfg->v_fc_config.timings.hsw = cfg->timings.hsw - 1;
+ video_cfg->v_fc_config.timings.hbp = cfg->timings.hbp;
+ video_cfg->v_fc_config.timings.hfp = cfg->timings.hfp;
+ video_cfg->hblank = cfg->timings.hfp +
+ cfg->timings.hbp + cfg->timings.hsw - 1;
+ video_cfg->v_fc_config.timings.vsync_level = cfg->timings.vsync_level;
+ video_cfg->v_fc_config.timings.y_res = cfg->timings.y_res;
+ video_cfg->v_fc_config.timings.vsw = cfg->timings.vsw;
+ video_cfg->v_fc_config.timings.vfp = cfg->timings.vfp;
+ video_cfg->v_fc_config.timings.vbp = cfg->timings.vbp;
+ video_cfg->vblank_osc = 0; /* Always 0 - need to confirm */
+ video_cfg->vblank = cfg->timings.vsw +
+ cfg->timings.vfp + cfg->timings.vbp;
+ video_cfg->v_fc_config.cm.mode = cfg->cm.mode;
+ video_cfg->v_fc_config.timings.interlace = cfg->timings.interlace;
+
+ /* info frame */
+ avi_cfg->db1_format = 0;
+ avi_cfg->db1_active_info = 0;
+ avi_cfg->db1_bar_info_dv = 0;
+ avi_cfg->db1_scan_info = 0;
+ avi_cfg->db2_colorimetry = 0;
+ avi_cfg->db2_aspect_ratio = 0;
+ avi_cfg->db2_active_fmt_ar = 0;
+ avi_cfg->db3_itc = 0;
+ avi_cfg->db3_ec = 0;
+ avi_cfg->db3_q_range = 0;
+ avi_cfg->db3_nup_scaling = 0;
+ avi_cfg->db4_videocode = 0;
+ avi_cfg->db5_pixel_repeat = 0;
+ avi_cfg->db6_7_line_eoftop = 0;
+ avi_cfg->db8_9_line_sofbottom = 0;
+ avi_cfg->db10_11_pixel_eofleft = 0;
+ avi_cfg->db12_13_pixel_sofright = 0;
+}
+
+/* DSS_HDMI_CORE_VIDEO_CONFIG */
+static void hdmi_core_video_config(struct hdmi_core_data *core,
+ struct hdmi_core_vid_config *cfg)
+{
+ void __iomem *base = core->base;
+ unsigned char r = 0;
+ bool vsync_pol, hsync_pol;
+
+ vsync_pol =
+ cfg->v_fc_config.timings.vsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
+ hsync_pol =
+ cfg->v_fc_config.timings.hsync_level == OMAPDSS_SIG_ACTIVE_HIGH;
+
+ /* Set hsync, vsync and data-enable polarity */
+ r = hdmi_read_reg(base, HDMI_CORE_FC_INVIDCONF);
+ r = FLD_MOD(r, vsync_pol, 6, 6);
+ r = FLD_MOD(r, hsync_pol, 5, 5);
+ r = FLD_MOD(r, cfg->data_enable_pol, 4, 4);
+ r = FLD_MOD(r, cfg->vblank_osc, 1, 1);
+ r = FLD_MOD(r, cfg->v_fc_config.timings.interlace, 0, 0);
+ hdmi_write_reg(base, HDMI_CORE_FC_INVIDCONF, r);
+
+ /* set x resolution */
+ REG_FLD_MOD(base, HDMI_CORE_FC_INHACTIV1,
+ cfg->v_fc_config.timings.x_res >> 8, 4, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_INHACTIV0,
+ cfg->v_fc_config.timings.x_res & 0xFF, 7, 0);
+
+ /* set y resolution */
+ REG_FLD_MOD(base, HDMI_CORE_FC_INVACTIV1,
+ cfg->v_fc_config.timings.y_res >> 8, 4, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_INVACTIV0,
+ cfg->v_fc_config.timings.y_res & 0xFF, 7, 0);
+
+ /* set horizontal blanking pixels */
+ REG_FLD_MOD(base, HDMI_CORE_FC_INHBLANK1, cfg->hblank >> 8, 4, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_INHBLANK0, cfg->hblank & 0xFF, 7, 0);
+
+ /* set vertial blanking pixels */
+ REG_FLD_MOD(base, HDMI_CORE_FC_INVBLANK, cfg->vblank, 7, 0);
+
+ /* set horizontal sync offset */
+ REG_FLD_MOD(base, HDMI_CORE_FC_HSYNCINDELAY1,
+ cfg->v_fc_config.timings.hfp >> 8, 4, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_HSYNCINDELAY0,
+ cfg->v_fc_config.timings.hfp & 0xFF, 7, 0);
+
+ /* set vertical sync offset */
+ REG_FLD_MOD(base, HDMI_CORE_FC_VSYNCINDELAY,
+ cfg->v_fc_config.timings.vfp, 7, 0);
+
+ /* set horizontal sync pulse width */
+ REG_FLD_MOD(base, HDMI_CORE_FC_HSYNCINWIDTH1,
+ (cfg->v_fc_config.timings.hsw >> 8), 1, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_HSYNCINWIDTH0,
+ cfg->v_fc_config.timings.hsw & 0xFF, 7, 0);
+
+ /* set vertical sync pulse width */
+ REG_FLD_MOD(base, HDMI_CORE_FC_VSYNCINWIDTH,
+ cfg->v_fc_config.timings.vsw, 5, 0);
+
+ /* select DVI mode */
+ REG_FLD_MOD(base, HDMI_CORE_FC_INVIDCONF,
+ cfg->v_fc_config.cm.mode, 3, 3);
+}
+
+static void hdmi_core_config_video_packetizer(struct hdmi_core_data *core)
+{
+ void __iomem *base = core->base;
+ int clr_depth = 0; /* 24 bit color depth */
+
+ /* COLOR_DEPTH */
+ REG_FLD_MOD(base, HDMI_CORE_VP_PR_CD, clr_depth, 7, 4);
+ /* BYPASS_EN */
+ REG_FLD_MOD(base, HDMI_CORE_VP_CONF, clr_depth ? 0 : 1, 6, 6);
+ /* PP_EN */
+ REG_FLD_MOD(base, HDMI_CORE_VP_CONF, clr_depth ? 1 : 0, 5, 5);
+ /* YCC422_EN */
+ REG_FLD_MOD(base, HDMI_CORE_VP_CONF, 0, 3, 3);
+ /* PP_STUFFING */
+ REG_FLD_MOD(base, HDMI_CORE_VP_STUFF, clr_depth ? 1 : 0, 1, 1);
+ /* YCC422_STUFFING */
+ REG_FLD_MOD(base, HDMI_CORE_VP_STUFF, 1, 2, 2);
+ /* OUTPUT_SELECTOR */
+ REG_FLD_MOD(base, HDMI_CORE_VP_CONF, clr_depth ? 0 : 2, 1, 0);
+}
+
+static void hdmi_core_config_csc(struct hdmi_core_data *core)
+{
+ int clr_depth = 0; /* 24 bit color depth */
+
+ /* CSC_COLORDEPTH */
+ REG_FLD_MOD(core->base, HDMI_CORE_CSC_SCALE, clr_depth, 7, 4);
+}
+
+static void hdmi_core_config_video_sampler(struct hdmi_core_data *core)
+{
+ int video_mapping = 1; /* for 24 bit color depth */
+
+ /* VIDEO_MAPPING */
+ REG_FLD_MOD(core->base, HDMI_CORE_TX_INVID0, video_mapping, 4, 0);
+}
+
+static void hdmi_core_aux_infoframe_avi_config(struct hdmi_core_data *core)
+{
+ void __iomem *base = core->base;
+ struct hdmi_core_infoframe_avi avi = core->avi_cfg;
+
+ REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF0, avi.db1_format, 1, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF0, avi.db1_active_info, 6, 6);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF0, avi.db1_bar_info_dv, 3, 2);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF0, avi.db1_scan_info, 5, 4);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF1, avi.db2_colorimetry, 7, 6);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF1, avi.db2_aspect_ratio, 5, 4);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF1, avi.db2_active_fmt_ar, 3, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF2, avi.db3_itc, 7, 7);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF2, avi.db3_ec, 6, 4);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF2, avi.db3_q_range, 3, 2);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AVICONF2, avi.db3_nup_scaling, 1, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AVIVID, avi.db4_videocode, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_PRCONF, avi.db5_pixel_repeat, 3, 0);
+}
+
+static void hdmi_core_csc_config(struct hdmi_core_data *core,
+ struct csc_table csc_coeff)
+{
+ void __iomem *base = core->base;
+
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A1_MSB, csc_coeff.a1 >> 8 , 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A1_LSB, csc_coeff.a1, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A2_MSB, csc_coeff.a2 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A2_LSB, csc_coeff.a2, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A3_MSB, csc_coeff.a3 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A3_LSB, csc_coeff.a3, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A4_MSB, csc_coeff.a4 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_A4_LSB, csc_coeff.a4, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B1_MSB, csc_coeff.b1 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B1_LSB, csc_coeff.b1, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B2_MSB, csc_coeff.b2 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B2_LSB, csc_coeff.b2, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B3_MSB, csc_coeff.b3 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B3_LSB, csc_coeff.b3, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B4_MSB, csc_coeff.b4 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_B4_LSB, csc_coeff.b4, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C1_MSB, csc_coeff.c1 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C1_LSB, csc_coeff.c1, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C2_MSB, csc_coeff.c2 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C2_LSB, csc_coeff.c2, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C3_MSB, csc_coeff.c3 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C3_LSB, csc_coeff.c3, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C4_MSB, csc_coeff.c4 >> 8, 6, 0);
+ REG_FLD_MOD(base, HDMI_CORE_CSC_COEF_C4_LSB, csc_coeff.c4, 7, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_MC_FLOWCTRL, 0x1, 0, 0);
+}
+
+static void hdmi_core_configure_range(struct hdmi_core_data *core)
+{
+ struct csc_table csc_coeff = { 0 };
+
+ /* support limited range with 24 bit color depth for now */
+ csc_coeff = csc_table_deepcolor[0];
+ core->avi_cfg.db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_LR;
+
+ hdmi_core_csc_config(core, csc_coeff);
+ hdmi_core_aux_infoframe_avi_config(core);
+}
+
+static void hdmi_core_enable_video_path(struct hdmi_core_data *core)
+{
+ void __iomem *base = core->base;
+
+ DSSDBG("hdmi_core_enable_video_path\n");
+
+ REG_FLD_MOD(base, HDMI_CORE_FC_CTRLDUR, 0x0C, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_EXCTRLDUR, 0x20, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_EXCTRLSPAC, 0x01, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_CH0PREAM, 0x0B, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_CH1PREAM, 0x16, 5, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_CH2PREAM, 0x21, 5, 0);
+ REG_FLD_MOD(base, HDMI_CORE_MC_CLKDIS, 0x00, 0, 0);
+ REG_FLD_MOD(base, HDMI_CORE_MC_CLKDIS, 0x00, 1, 1);
+}
+
+static void hdmi_core_mask_interrupts(struct hdmi_core_data *core)
+{
+ void __iomem *base = core->base;
+
+ /* Master IRQ mask */
+ REG_FLD_MOD(base, HDMI_CORE_IH_MUTE, 0x3, 1, 0);
+
+ /* Mask all the interrupts in HDMI core */
+
+ REG_FLD_MOD(base, HDMI_CORE_VP_MASK, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_MASK0, 0xe7, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_MASK1, 0xfb, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_MASK2, 0x3, 1, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_AUD_INT, 0x3, 3, 2);
+ REG_FLD_MOD(base, HDMI_CORE_AUD_GP_MASK, 0x3, 1, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_CEC_MASK, 0x7f, 6, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 6, 6);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_CTLINT, 0x1, 2, 2);
+ REG_FLD_MOD(base, HDMI_CORE_I2CM_INT, 0x1, 2, 2);
+
+ REG_FLD_MOD(base, HDMI_CORE_PHY_MASK0, 0xf3, 7, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_IH_PHY_STAT0, 0xff, 7, 0);
+
+ /* Clear all the current interrupt bits */
+
+ REG_FLD_MOD(base, HDMI_CORE_IH_VP_STAT0, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT0, 0xe7, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT1, 0xfb, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT2, 0x3, 1, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_IH_AS_STAT0, 0x7, 2, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_IH_CEC_STAT0, 0x7f, 6, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_IH_I2CM_STAT0, 0x3, 1, 0);
+
+ REG_FLD_MOD(base, HDMI_CORE_IH_PHY_STAT0, 0xff, 7, 0);
+}
+
+static void hdmi_core_enable_interrupts(struct hdmi_core_data *core)
+{
+ /* Unmute interrupts */
+ REG_FLD_MOD(core->base, HDMI_CORE_IH_MUTE, 0x0, 1, 0);
+}
+
+int hdmi5_core_handle_irqs(struct hdmi_core_data *core)
+{
+ void __iomem *base = core->base;
+
+ REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT0, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT1, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_FC_STAT2, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_AS_STAT0, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_PHY_STAT0, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_I2CM_STAT0, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_CEC_STAT0, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_VP_STAT0, 0xff, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_IH_I2CMPHY_STAT0, 0xff, 7, 0);
+
+ return 0;
+}
+
+void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
+ struct hdmi_config *cfg)
+{
+ struct omap_video_timings video_timing;
+ struct hdmi_video_format video_format;
+ struct hdmi_core_vid_config v_core_cfg;
+ struct hdmi_core_infoframe_avi *avi_cfg = &core->avi_cfg;
+
+ hdmi_core_mask_interrupts(core);
+
+ hdmi_core_init(&v_core_cfg, avi_cfg, cfg);
+
+ hdmi_wp_init_vid_fmt_timings(&video_format, &video_timing, cfg);
+
+ hdmi_wp_video_config_timing(wp, &video_timing);
+
+ /* video config */
+ video_format.packing_mode = HDMI_PACK_24b_RGB_YUV444_YUV422;
+
+ hdmi_wp_video_config_format(wp, &video_format);
+
+ hdmi_wp_video_config_interface(wp, &video_timing);
+
+ hdmi_core_configure_range(core);
+
+ /*
+ * configure core video part, set software reset in the core
+ */
+ v_core_cfg.packet_mode = HDMI_PACKETMODE24BITPERPIXEL;
+
+ hdmi_core_video_config(core, &v_core_cfg);
+
+ hdmi_core_config_video_packetizer(core);
+ hdmi_core_config_csc(core);
+ hdmi_core_config_video_sampler(core);
+
+ /*
+ * configure packet info frame video see doc CEA861-D page 65
+ */
+ avi_cfg->db1_format = HDMI_INFOFRAME_AVI_DB1Y_RGB;
+ avi_cfg->db1_active_info =
+ HDMI_INFOFRAME_AVI_DB1A_ACTIVE_FORMAT_OFF;
+ avi_cfg->db1_bar_info_dv = HDMI_INFOFRAME_AVI_DB1B_NO;
+ avi_cfg->db1_scan_info = HDMI_INFOFRAME_AVI_DB1S_0;
+ avi_cfg->db2_colorimetry = HDMI_INFOFRAME_AVI_DB2C_NO;
+ avi_cfg->db2_aspect_ratio = HDMI_INFOFRAME_AVI_DB2M_NO;
+ avi_cfg->db2_active_fmt_ar = HDMI_INFOFRAME_AVI_DB2R_SAME;
+ avi_cfg->db3_itc = HDMI_INFOFRAME_AVI_DB3ITC_NO;
+ avi_cfg->db3_ec = HDMI_INFOFRAME_AVI_DB3EC_XVYUV601;
+ avi_cfg->db3_q_range = HDMI_INFOFRAME_AVI_DB3Q_DEFAULT;
+ avi_cfg->db3_nup_scaling = HDMI_INFOFRAME_AVI_DB3SC_NO;
+ avi_cfg->db4_videocode = cfg->cm.code;
+ avi_cfg->db5_pixel_repeat = HDMI_INFOFRAME_AVI_DB5PR_NO;
+ avi_cfg->db6_7_line_eoftop = 0;
+ avi_cfg->db8_9_line_sofbottom = 0;
+ avi_cfg->db10_11_pixel_eofleft = 0;
+ avi_cfg->db12_13_pixel_sofright = 0;
+
+ hdmi_core_aux_infoframe_avi_config(core);
+
+ hdmi_core_enable_video_path(core);
+
+ hdmi_core_enable_interrupts(core);
+}
+
+
+#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
+
+static void hdmi5_core_audio_config(struct hdmi_core_data *core,
+ struct hdmi_core_audio_config *cfg)
+{
+ void __iomem *base = core->base;
+ u8 val;
+
+ /* Mute audio before configuring */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCONF, 0xf, 7, 4);
+
+ /* Set the N parameter */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_N1, cfg->n, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_AUD_N2, cfg->n >> 8, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_AUD_N3, cfg->n >> 16, 3, 0);
+
+ /*
+ * CTS manual mode. Automatic mode is not supported when using audio
+ * parallel interface.
+ */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_CTS3, 1, 4, 4);
+ REG_FLD_MOD(base, HDMI_CORE_AUD_CTS1, cfg->cts, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_AUD_CTS2, cfg->cts >> 8, 7, 0);
+ REG_FLD_MOD(base, HDMI_CORE_AUD_CTS3, cfg->cts >> 16, 3, 0);
+
+ /* Layout of Audio Sample Packets: 2-channel or multichannels */
+ if (cfg->layout == HDMI_AUDIO_LAYOUT_2CH)
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCONF, 0, 0, 0);
+ else
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCONF, 1, 0, 0);
+
+ /* Configure IEC-609580 Validity bits */
+ /* Channel 0 is valid */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, 0, 0, 0);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, 0, 4, 4);
+
+ if (cfg->layout == HDMI_AUDIO_LAYOUT_2CH)
+ val = 1;
+ else
+ val = 0;
+
+ /* Channels 1, 2 setting */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 1, 1);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 5, 5);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 2, 2);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 6, 6);
+ /* Channel 3 setting */
+ if (cfg->layout == HDMI_AUDIO_LAYOUT_6CH)
+ val = 1;
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 3, 3);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSV, val, 7, 7);
+
+ /* Configure IEC-60958 User bits */
+ /* TODO: should be set by user. */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSU, 0, 7, 0);
+
+ /* Configure IEC-60958 Channel Status word */
+ /* CGMSA */
+ val = cfg->iec60958_cfg->status[5] & IEC958_AES5_CON_CGMSA;
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(0), val, 5, 4);
+
+ /* Copyright */
+ val = (cfg->iec60958_cfg->status[0] &
+ IEC958_AES0_CON_NOT_COPYRIGHT) >> 2;
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(0), val, 0, 0);
+
+ /* Category */
+ hdmi_write_reg(base, HDMI_CORE_FC_AUDSCHNLS(1),
+ cfg->iec60958_cfg->status[1]);
+
+ /* PCM audio mode */
+ val = (cfg->iec60958_cfg->status[0] & IEC958_AES0_CON_MODE) >> 6;
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 6, 4);
+
+ /* Source number */
+ val = cfg->iec60958_cfg->status[2] & IEC958_AES2_CON_SOURCE;
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 3, 4);
+
+ /* Channel number right 0 */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(3), 2, 3, 0);
+ /* Channel number right 1*/
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(3), 4, 7, 4);
+ /* Channel number right 2 */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(4), 6, 3, 0);
+ /* Channel number right 3*/
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(4), 8, 7, 4);
+ /* Channel number left 0 */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(5), 1, 3, 0);
+ /* Channel number left 1*/
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(5), 3, 7, 4);
+ /* Channel number left 2 */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(6), 5, 3, 0);
+ /* Channel number left 3*/
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(6), 7, 7, 4);
+
+ /* Clock accuracy and sample rate */
+ hdmi_write_reg(base, HDMI_CORE_FC_AUDSCHNLS(7),
+ cfg->iec60958_cfg->status[3]);
+
+ /* Original sample rate and word length */
+ hdmi_write_reg(base, HDMI_CORE_FC_AUDSCHNLS(8),
+ cfg->iec60958_cfg->status[4]);
+
+ /* Enable FIFO empty and full interrupts */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_INT, 3, 3, 2);
+
+ /* Configure GPA */
+ /* select HBR/SPDIF interfaces */
+ if (cfg->layout == HDMI_AUDIO_LAYOUT_2CH) {
+ /* select HBR/SPDIF interfaces */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_CONF0, 0, 5, 5);
+ /* enable two channels in GPA */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF1, 3, 7, 0);
+ } else if (cfg->layout == HDMI_AUDIO_LAYOUT_6CH) {
+ /* select HBR/SPDIF interfaces */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_CONF0, 0, 5, 5);
+ /* enable six channels in GPA */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF1, 0x3F, 7, 0);
+ } else {
+ /* select HBR/SPDIF interfaces */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_CONF0, 0, 5, 5);
+ /* enable eight channels in GPA */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF1, 0xFF, 7, 0);
+ }
+
+ /* disable HBR */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF2, 0, 0, 0);
+ /* enable PCUV */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_GP_CONF2, 1, 1, 1);
+ /* enable GPA FIFO full and empty mask */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_GP_MASK, 3, 1, 0);
+ /* set polarity of GPA FIFO empty interrupts */
+ REG_FLD_MOD(base, HDMI_CORE_AUD_GP_POL, 1, 0, 0);
+
+ /* unmute audio */
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCONF, 0, 7, 4);
+}
+
+static void hdmi5_core_audio_infoframe_cfg(struct hdmi_core_data *core,
+ struct snd_cea_861_aud_if *info_aud)
+{
+ void __iomem *base = core->base;
+
+ /* channel count and coding type fields in AUDICONF0 are swapped */
+ hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF0,
+ (info_aud->db1_ct_cc & CEA861_AUDIO_INFOFRAME_DB1CC) << 4 |
+ (info_aud->db1_ct_cc & CEA861_AUDIO_INFOFRAME_DB1CT) >> 4);
+
+ hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF1, info_aud->db2_sf_ss);
+ hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF2, info_aud->db4_ca);
+ hdmi_write_reg(base, HDMI_CORE_FC_AUDICONF3, info_aud->db5_dminh_lsv);
+}
+
+int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
+ struct omap_dss_audio *audio, u32 pclk)
+{
+ struct hdmi_audio_format audio_format;
+ struct hdmi_audio_dma audio_dma;
+ struct hdmi_core_audio_config core_cfg;
+ int err, n, cts, channel_count;
+ unsigned int fs_nr;
+ bool word_length_16b = false;
+
+ if (!audio || !audio->iec || !audio->cea || !core)
+ return -EINVAL;
+
+ core_cfg.iec60958_cfg = audio->iec;
+
+ if (!(audio->iec->status[4] & IEC958_AES4_CON_MAX_WORDLEN_24) &&
+ (audio->iec->status[4] & IEC958_AES4_CON_WORDLEN_20_16))
+ word_length_16b = true;
+
+ /* only 16-bit word length supported atm */
+ if (!word_length_16b)
+ return -EINVAL;
+
+ switch (audio->iec->status[3] & IEC958_AES3_CON_FS) {
+ case IEC958_AES3_CON_FS_32000:
+ fs_nr = 32000;
+ break;
+ case IEC958_AES3_CON_FS_44100:
+ fs_nr = 44100;
+ break;
+ case IEC958_AES3_CON_FS_48000:
+ fs_nr = 48000;
+ break;
+ case IEC958_AES3_CON_FS_88200:
+ fs_nr = 88200;
+ break;
+ case IEC958_AES3_CON_FS_96000:
+ fs_nr = 96000;
+ break;
+ case IEC958_AES3_CON_FS_176400:
+ fs_nr = 176400;
+ break;
+ case IEC958_AES3_CON_FS_192000:
+ fs_nr = 192000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = hdmi_compute_acr(pclk, fs_nr, &n, &cts);
+ core_cfg.n = n;
+ core_cfg.cts = cts;
+
+ /* Audio channels settings */
+ channel_count = (audio->cea->db1_ct_cc & CEA861_AUDIO_INFOFRAME_DB1CC)
+ + 1;
+
+ if (channel_count == 2)
+ core_cfg.layout = HDMI_AUDIO_LAYOUT_2CH;
+ else if (channel_count == 6)
+ core_cfg.layout = HDMI_AUDIO_LAYOUT_6CH;
+ else
+ core_cfg.layout = HDMI_AUDIO_LAYOUT_8CH;
+
+ /* DMA settings */
+ if (word_length_16b)
+ audio_dma.transfer_size = 0x10;
+ else
+ audio_dma.transfer_size = 0x20;
+ audio_dma.block_size = 0xC0;
+ audio_dma.mode = HDMI_AUDIO_TRANSF_DMA;
+ audio_dma.fifo_threshold = 0x20; /* in number of samples */
+
+ /* audio FIFO format settings for 16-bit samples*/
+ audio_format.samples_per_word = HDMI_AUDIO_ONEWORD_TWOSAMPLES;
+ audio_format.sample_size = HDMI_AUDIO_SAMPLE_16BITS;
+ audio_format.justification = HDMI_AUDIO_JUSTIFY_LEFT;
+
+ /* only LPCM atm */
+ audio_format.type = HDMI_AUDIO_TYPE_LPCM;
+
+ /* disable start/stop signals of IEC 60958 blocks */
+ audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON;
+
+ /* configure DMA and audio FIFO format*/
+ hdmi_wp_audio_config_dma(wp, &audio_dma);
+ hdmi_wp_audio_config_format(wp, &audio_format);
+
+ /* configure the core */
+ hdmi5_core_audio_config(core, &core_cfg);
+
+ /* configure CEA 861 audio infoframe */
+ hdmi5_core_audio_infoframe_cfg(core, audio->cea);
+
+ return 0;
+}
+#endif
+
+int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core)
+{
+ struct resource *res;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "core");
+ if (!res) {
+ DSSERR("can't get CORE IORESOURCE_MEM HDMI\n");
+ return -EINVAL;
+ }
+
+ core->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(core->base)) {
+ DSSERR("can't ioremap HDMI core\n");
+ return PTR_ERR(core->base);
+ }
+
+ return 0;
+}
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5_core.h b/drivers/video/fbdev/omap2/dss/hdmi5_core.h
new file mode 100644
index 000000000000..ce7e9f376f04
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/hdmi5_core.h
@@ -0,0 +1,306 @@
+/*
+ * HDMI driver definition for TI OMAP5 processors.
+ *
+ * Copyright (C) 2011-2012 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _HDMI5_CORE_H_
+#define _HDMI5_CORE_H_
+
+#include "hdmi.h"
+
+/* HDMI IP Core System */
+
+/* HDMI Identification */
+#define HDMI_CORE_DESIGN_ID 0x00000
+#define HDMI_CORE_REVISION_ID 0x00004
+#define HDMI_CORE_PRODUCT_ID0 0x00008
+#define HDMI_CORE_PRODUCT_ID1 0x0000C
+#define HDMI_CORE_CONFIG0_ID 0x00010
+#define HDMI_CORE_CONFIG1_ID 0x00014
+#define HDMI_CORE_CONFIG2_ID 0x00018
+#define HDMI_CORE_CONFIG3_ID 0x0001C
+
+/* HDMI Interrupt */
+#define HDMI_CORE_IH_FC_STAT0 0x00400
+#define HDMI_CORE_IH_FC_STAT1 0x00404
+#define HDMI_CORE_IH_FC_STAT2 0x00408
+#define HDMI_CORE_IH_AS_STAT0 0x0040C
+#define HDMI_CORE_IH_PHY_STAT0 0x00410
+#define HDMI_CORE_IH_I2CM_STAT0 0x00414
+#define HDMI_CORE_IH_CEC_STAT0 0x00418
+#define HDMI_CORE_IH_VP_STAT0 0x0041C
+#define HDMI_CORE_IH_I2CMPHY_STAT0 0x00420
+#define HDMI_CORE_IH_MUTE 0x007FC
+
+/* HDMI Video Sampler */
+#define HDMI_CORE_TX_INVID0 0x00800
+#define HDMI_CORE_TX_INSTUFFING 0x00804
+#define HDMI_CORE_TX_RGYDATA0 0x00808
+#define HDMI_CORE_TX_RGYDATA1 0x0080C
+#define HDMI_CORE_TX_RCRDATA0 0x00810
+#define HDMI_CORE_TX_RCRDATA1 0x00814
+#define HDMI_CORE_TX_BCBDATA0 0x00818
+#define HDMI_CORE_TX_BCBDATA1 0x0081C
+
+/* HDMI Video Packetizer */
+#define HDMI_CORE_VP_STATUS 0x02000
+#define HDMI_CORE_VP_PR_CD 0x02004
+#define HDMI_CORE_VP_STUFF 0x02008
+#define HDMI_CORE_VP_REMAP 0x0200C
+#define HDMI_CORE_VP_CONF 0x02010
+#define HDMI_CORE_VP_STAT 0x02014
+#define HDMI_CORE_VP_INT 0x02018
+#define HDMI_CORE_VP_MASK 0x0201C
+#define HDMI_CORE_VP_POL 0x02020
+
+/* Frame Composer */
+#define HDMI_CORE_FC_INVIDCONF 0x04000
+#define HDMI_CORE_FC_INHACTIV0 0x04004
+#define HDMI_CORE_FC_INHACTIV1 0x04008
+#define HDMI_CORE_FC_INHBLANK0 0x0400C
+#define HDMI_CORE_FC_INHBLANK1 0x04010
+#define HDMI_CORE_FC_INVACTIV0 0x04014
+#define HDMI_CORE_FC_INVACTIV1 0x04018
+#define HDMI_CORE_FC_INVBLANK 0x0401C
+#define HDMI_CORE_FC_HSYNCINDELAY0 0x04020
+#define HDMI_CORE_FC_HSYNCINDELAY1 0x04024
+#define HDMI_CORE_FC_HSYNCINWIDTH0 0x04028
+#define HDMI_CORE_FC_HSYNCINWIDTH1 0x0402C
+#define HDMI_CORE_FC_VSYNCINDELAY 0x04030
+#define HDMI_CORE_FC_VSYNCINWIDTH 0x04034
+#define HDMI_CORE_FC_INFREQ0 0x04038
+#define HDMI_CORE_FC_INFREQ1 0x0403C
+#define HDMI_CORE_FC_INFREQ2 0x04040
+#define HDMI_CORE_FC_CTRLDUR 0x04044
+#define HDMI_CORE_FC_EXCTRLDUR 0x04048
+#define HDMI_CORE_FC_EXCTRLSPAC 0x0404C
+#define HDMI_CORE_FC_CH0PREAM 0x04050
+#define HDMI_CORE_FC_CH1PREAM 0x04054
+#define HDMI_CORE_FC_CH2PREAM 0x04058
+#define HDMI_CORE_FC_AVICONF3 0x0405C
+#define HDMI_CORE_FC_GCP 0x04060
+#define HDMI_CORE_FC_AVICONF0 0x04064
+#define HDMI_CORE_FC_AVICONF1 0x04068
+#define HDMI_CORE_FC_AVICONF2 0x0406C
+#define HDMI_CORE_FC_AVIVID 0x04070
+#define HDMI_CORE_FC_AVIETB0 0x04074
+#define HDMI_CORE_FC_AVIETB1 0x04078
+#define HDMI_CORE_FC_AVISBB0 0x0407C
+#define HDMI_CORE_FC_AVISBB1 0x04080
+#define HDMI_CORE_FC_AVIELB0 0x04084
+#define HDMI_CORE_FC_AVIELB1 0x04088
+#define HDMI_CORE_FC_AVISRB0 0x0408C
+#define HDMI_CORE_FC_AVISRB1 0x04090
+#define HDMI_CORE_FC_AUDICONF0 0x04094
+#define HDMI_CORE_FC_AUDICONF1 0x04098
+#define HDMI_CORE_FC_AUDICONF2 0x0409C
+#define HDMI_CORE_FC_AUDICONF3 0x040A0
+#define HDMI_CORE_FC_VSDIEEEID0 0x040A4
+#define HDMI_CORE_FC_VSDSIZE 0x040A8
+#define HDMI_CORE_FC_VSDIEEEID1 0x040C0
+#define HDMI_CORE_FC_VSDIEEEID2 0x040C4
+#define HDMI_CORE_FC_VSDPAYLOAD(n) (n * 4 + 0x040C8)
+#define HDMI_CORE_FC_SPDVENDORNAME(n) (n * 4 + 0x04128)
+#define HDMI_CORE_FC_SPDPRODUCTNAME(n) (n * 4 + 0x04148)
+#define HDMI_CORE_FC_SPDDEVICEINF 0x04188
+#define HDMI_CORE_FC_AUDSCONF 0x0418C
+#define HDMI_CORE_FC_AUDSSTAT 0x04190
+#define HDMI_CORE_FC_AUDSV 0x04194
+#define HDMI_CORE_FC_AUDSU 0x04198
+#define HDMI_CORE_FC_AUDSCHNLS(n) (n * 4 + 0x0419C)
+#define HDMI_CORE_FC_CTRLQHIGH 0x041CC
+#define HDMI_CORE_FC_CTRLQLOW 0x041D0
+#define HDMI_CORE_FC_ACP0 0x041D4
+#define HDMI_CORE_FC_ACP(n) ((16-n) * 4 + 0x04208)
+#define HDMI_CORE_FC_ISCR1_0 0x04248
+#define HDMI_CORE_FC_ISCR1(n) ((16-n) * 4 + 0x0424C)
+#define HDMI_CORE_FC_ISCR2(n) ((15-n) * 4 + 0x0428C)
+#define HDMI_CORE_FC_DATAUTO0 0x042CC
+#define HDMI_CORE_FC_DATAUTO1 0x042D0
+#define HDMI_CORE_FC_DATAUTO2 0x042D4
+#define HDMI_CORE_FC_DATMAN 0x042D8
+#define HDMI_CORE_FC_DATAUTO3 0x042DC
+#define HDMI_CORE_FC_RDRB(n) (n * 4 + 0x042E0)
+#define HDMI_CORE_FC_STAT0 0x04340
+#define HDMI_CORE_FC_INT0 0x04344
+#define HDMI_CORE_FC_MASK0 0x04348
+#define HDMI_CORE_FC_POL0 0x0434C
+#define HDMI_CORE_FC_STAT1 0x04350
+#define HDMI_CORE_FC_INT1 0x04354
+#define HDMI_CORE_FC_MASK1 0x04358
+#define HDMI_CORE_FC_POL1 0x0435C
+#define HDMI_CORE_FC_STAT2 0x04360
+#define HDMI_CORE_FC_INT2 0x04364
+#define HDMI_CORE_FC_MASK2 0x04368
+#define HDMI_CORE_FC_POL2 0x0436C
+#define HDMI_CORE_FC_PRCONF 0x04380
+#define HDMI_CORE_FC_GMD_STAT 0x04400
+#define HDMI_CORE_FC_GMD_EN 0x04404
+#define HDMI_CORE_FC_GMD_UP 0x04408
+#define HDMI_CORE_FC_GMD_CONF 0x0440C
+#define HDMI_CORE_FC_GMD_HB 0x04410
+#define HDMI_CORE_FC_GMD_PB(n) (n * 4 + 0x04414)
+#define HDMI_CORE_FC_DBGFORCE 0x04800
+#define HDMI_CORE_FC_DBGAUD0CH0 0x04804
+#define HDMI_CORE_FC_DBGAUD1CH0 0x04808
+#define HDMI_CORE_FC_DBGAUD2CH0 0x0480C
+#define HDMI_CORE_FC_DBGAUD0CH1 0x04810
+#define HDMI_CORE_FC_DBGAUD1CH1 0x04814
+#define HDMI_CORE_FC_DBGAUD2CH1 0x04818
+#define HDMI_CORE_FC_DBGAUD0CH2 0x0481C
+#define HDMI_CORE_FC_DBGAUD1CH2 0x04820
+#define HDMI_CORE_FC_DBGAUD2CH2 0x04824
+#define HDMI_CORE_FC_DBGAUD0CH3 0x04828
+#define HDMI_CORE_FC_DBGAUD1CH3 0x0482C
+#define HDMI_CORE_FC_DBGAUD2CH3 0x04830
+#define HDMI_CORE_FC_DBGAUD0CH4 0x04834
+#define HDMI_CORE_FC_DBGAUD1CH4 0x04838
+#define HDMI_CORE_FC_DBGAUD2CH4 0x0483C
+#define HDMI_CORE_FC_DBGAUD0CH5 0x04840
+#define HDMI_CORE_FC_DBGAUD1CH5 0x04844
+#define HDMI_CORE_FC_DBGAUD2CH5 0x04848
+#define HDMI_CORE_FC_DBGAUD0CH6 0x0484C
+#define HDMI_CORE_FC_DBGAUD1CH6 0x04850
+#define HDMI_CORE_FC_DBGAUD2CH6 0x04854
+#define HDMI_CORE_FC_DBGAUD0CH7 0x04858
+#define HDMI_CORE_FC_DBGAUD1CH7 0x0485C
+#define HDMI_CORE_FC_DBGAUD2CH7 0x04860
+#define HDMI_CORE_FC_DBGTMDS0 0x04864
+#define HDMI_CORE_FC_DBGTMDS1 0x04868
+#define HDMI_CORE_FC_DBGTMDS2 0x0486C
+#define HDMI_CORE_PHY_MASK0 0x0C018
+#define HDMI_CORE_PHY_I2CM_INT_ADDR 0x0C09C
+#define HDMI_CORE_PHY_I2CM_CTLINT_ADDR 0x0C0A0
+
+/* HDMI Audio */
+#define HDMI_CORE_AUD_CONF0 0x0C400
+#define HDMI_CORE_AUD_CONF1 0x0C404
+#define HDMI_CORE_AUD_INT 0x0C408
+#define HDMI_CORE_AUD_N1 0x0C800
+#define HDMI_CORE_AUD_N2 0x0C804
+#define HDMI_CORE_AUD_N3 0x0C808
+#define HDMI_CORE_AUD_CTS1 0x0C80C
+#define HDMI_CORE_AUD_CTS2 0x0C810
+#define HDMI_CORE_AUD_CTS3 0x0C814
+#define HDMI_CORE_AUD_INCLKFS 0x0C818
+#define HDMI_CORE_AUD_CC08 0x0CC08
+#define HDMI_CORE_AUD_GP_CONF0 0x0D400
+#define HDMI_CORE_AUD_GP_CONF1 0x0D404
+#define HDMI_CORE_AUD_GP_CONF2 0x0D408
+#define HDMI_CORE_AUD_D010 0x0D010
+#define HDMI_CORE_AUD_GP_STAT 0x0D40C
+#define HDMI_CORE_AUD_GP_INT 0x0D410
+#define HDMI_CORE_AUD_GP_POL 0x0D414
+#define HDMI_CORE_AUD_GP_MASK 0x0D418
+
+/* HDMI Main Controller */
+#define HDMI_CORE_MC_CLKDIS 0x10004
+#define HDMI_CORE_MC_SWRSTZREQ 0x10008
+#define HDMI_CORE_MC_FLOWCTRL 0x10010
+#define HDMI_CORE_MC_PHYRSTZ 0x10014
+#define HDMI_CORE_MC_LOCKONCLOCK 0x10018
+
+/* HDMI COLOR SPACE CONVERTER */
+#define HDMI_CORE_CSC_CFG 0x10400
+#define HDMI_CORE_CSC_SCALE 0x10404
+#define HDMI_CORE_CSC_COEF_A1_MSB 0x10408
+#define HDMI_CORE_CSC_COEF_A1_LSB 0x1040C
+#define HDMI_CORE_CSC_COEF_A2_MSB 0x10410
+#define HDMI_CORE_CSC_COEF_A2_LSB 0x10414
+#define HDMI_CORE_CSC_COEF_A3_MSB 0x10418
+#define HDMI_CORE_CSC_COEF_A3_LSB 0x1041C
+#define HDMI_CORE_CSC_COEF_A4_MSB 0x10420
+#define HDMI_CORE_CSC_COEF_A4_LSB 0x10424
+#define HDMI_CORE_CSC_COEF_B1_MSB 0x10428
+#define HDMI_CORE_CSC_COEF_B1_LSB 0x1042C
+#define HDMI_CORE_CSC_COEF_B2_MSB 0x10430
+#define HDMI_CORE_CSC_COEF_B2_LSB 0x10434
+#define HDMI_CORE_CSC_COEF_B3_MSB 0x10438
+#define HDMI_CORE_CSC_COEF_B3_LSB 0x1043C
+#define HDMI_CORE_CSC_COEF_B4_MSB 0x10440
+#define HDMI_CORE_CSC_COEF_B4_LSB 0x10444
+#define HDMI_CORE_CSC_COEF_C1_MSB 0x10448
+#define HDMI_CORE_CSC_COEF_C1_LSB 0x1044C
+#define HDMI_CORE_CSC_COEF_C2_MSB 0x10450
+#define HDMI_CORE_CSC_COEF_C2_LSB 0x10454
+#define HDMI_CORE_CSC_COEF_C3_MSB 0x10458
+#define HDMI_CORE_CSC_COEF_C3_LSB 0x1045C
+#define HDMI_CORE_CSC_COEF_C4_MSB 0x10460
+#define HDMI_CORE_CSC_COEF_C4_LSB 0x10464
+
+/* HDMI HDCP */
+#define HDMI_CORE_HDCP_MASK 0x14020
+
+/* HDMI CEC */
+#define HDMI_CORE_CEC_MASK 0x17408
+
+/* HDMI I2C Master */
+#define HDMI_CORE_I2CM_SLAVE 0x157C8
+#define HDMI_CORE_I2CM_ADDRESS 0x157CC
+#define HDMI_CORE_I2CM_DATAO 0x157D0
+#define HDMI_CORE_I2CM_DATAI 0X157D4
+#define HDMI_CORE_I2CM_OPERATION 0x157D8
+#define HDMI_CORE_I2CM_INT 0x157DC
+#define HDMI_CORE_I2CM_CTLINT 0x157E0
+#define HDMI_CORE_I2CM_DIV 0x157E4
+#define HDMI_CORE_I2CM_SEGADDR 0x157E8
+#define HDMI_CORE_I2CM_SOFTRSTZ 0x157EC
+#define HDMI_CORE_I2CM_SEGPTR 0x157F0
+#define HDMI_CORE_I2CM_SS_SCL_HCNT_1_ADDR 0x157F4
+#define HDMI_CORE_I2CM_SS_SCL_HCNT_0_ADDR 0x157F8
+#define HDMI_CORE_I2CM_SS_SCL_LCNT_1_ADDR 0x157FC
+#define HDMI_CORE_I2CM_SS_SCL_LCNT_0_ADDR 0x15800
+#define HDMI_CORE_I2CM_FS_SCL_HCNT_1_ADDR 0x15804
+#define HDMI_CORE_I2CM_FS_SCL_HCNT_0_ADDR 0x15808
+#define HDMI_CORE_I2CM_FS_SCL_LCNT_1_ADDR 0x1580C
+#define HDMI_CORE_I2CM_FS_SCL_LCNT_0_ADDR 0x15810
+#define HDMI_CORE_I2CM_SDA_HOLD_ADDR 0x15814
+
+enum hdmi_core_packet_mode {
+ HDMI_PACKETMODERESERVEDVALUE = 0,
+ HDMI_PACKETMODE24BITPERPIXEL = 4,
+ HDMI_PACKETMODE30BITPERPIXEL = 5,
+ HDMI_PACKETMODE36BITPERPIXEL = 6,
+ HDMI_PACKETMODE48BITPERPIXEL = 7,
+};
+
+struct hdmi_core_vid_config {
+ struct hdmi_config v_fc_config;
+ enum hdmi_core_packet_mode packet_mode;
+ int data_enable_pol;
+ int vblank_osc;
+ int hblank;
+ int vblank;
+};
+
+struct csc_table {
+ u16 a1, a2, a3, a4;
+ u16 b1, b2, b3, b4;
+ u16 c1, c2, c3, c4;
+};
+
+int hdmi5_read_edid(struct hdmi_core_data *core, u8 *edid, int len);
+void hdmi5_core_dump(struct hdmi_core_data *core, struct seq_file *s);
+int hdmi5_core_handle_irqs(struct hdmi_core_data *core);
+void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
+ struct hdmi_config *cfg);
+int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core);
+
+#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
+int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
+ struct omap_dss_audio *audio, u32 pclk);
+#endif
+#endif
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_common.c b/drivers/video/fbdev/omap2/dss/hdmi_common.c
index 0b12a3f62fe1..9a2c39cf297f 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_common.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_common.c
@@ -17,6 +17,7 @@
#include <linux/kernel.h>
#include <linux/err.h>
+#include <linux/of.h>
#include <video/omapdss.h>
#include "hdmi.h"
@@ -323,6 +324,46 @@ end:
return cm;
}
+int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep,
+ struct hdmi_phy_data *phy)
+{
+ struct property *prop;
+ int r, len;
+
+ prop = of_find_property(ep, "lanes", &len);
+ if (prop) {
+ u32 lanes[8];
+
+ if (len / sizeof(u32) != ARRAY_SIZE(lanes)) {
+ dev_err(&pdev->dev, "bad number of lanes\n");
+ return -EINVAL;
+ }
+
+ r = of_property_read_u32_array(ep, "lanes", lanes,
+ ARRAY_SIZE(lanes));
+ if (r) {
+ dev_err(&pdev->dev, "failed to read lane data\n");
+ return r;
+ }
+
+ r = hdmi_phy_parse_lanes(phy, lanes);
+ if (r) {
+ dev_err(&pdev->dev, "failed to parse lane data\n");
+ return r;
+ }
+ } else {
+ static const u32 default_lanes[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+
+ r = hdmi_phy_parse_lanes(phy, default_lanes);
+ if (WARN_ON(r)) {
+ dev_err(&pdev->dev, "failed to parse lane data\n");
+ return r;
+ }
+ }
+
+ return 0;
+}
+
#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts)
{
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_phy.c b/drivers/video/fbdev/omap2/dss/hdmi_phy.c
index dd376ce8da01..e007ac892d79 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_phy.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_phy.c
@@ -12,11 +12,22 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <video/omapdss.h>
#include "dss.h"
#include "hdmi.h"
+struct hdmi_phy_features {
+ bool bist_ctrl;
+ bool calc_freqout;
+ bool ldo_voltage;
+ unsigned long dcofreq_min;
+ unsigned long max_phy;
+};
+
+static const struct hdmi_phy_features *phy_feat;
+
void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s)
{
#define DUMPPHY(r) seq_printf(s, "%-35s %08x\n", #r,\
@@ -26,53 +37,104 @@ void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s)
DUMPPHY(HDMI_TXPHY_DIGITAL_CTRL);
DUMPPHY(HDMI_TXPHY_POWER_CTRL);
DUMPPHY(HDMI_TXPHY_PAD_CFG_CTRL);
+ if (phy_feat->bist_ctrl)
+ DUMPPHY(HDMI_TXPHY_BIST_CONTROL);
}
-static irqreturn_t hdmi_irq_handler(int irq, void *data)
+int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes)
{
- struct hdmi_wp_data *wp = data;
- u32 irqstatus;
-
- irqstatus = hdmi_wp_get_irqstatus(wp);
- hdmi_wp_set_irqstatus(wp, irqstatus);
-
- if ((irqstatus & HDMI_IRQ_LINK_CONNECT) &&
- irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
- /*
- * If we get both connect and disconnect interrupts at the same
- * time, turn off the PHY, clear interrupts, and restart, which
- * raises connect interrupt if a cable is connected, or nothing
- * if cable is not connected.
- */
- hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
-
- hdmi_wp_set_irqstatus(wp, HDMI_IRQ_LINK_CONNECT |
- HDMI_IRQ_LINK_DISCONNECT);
-
- hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
- } else if (irqstatus & HDMI_IRQ_LINK_CONNECT) {
- hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_TXON);
- } else if (irqstatus & HDMI_IRQ_LINK_DISCONNECT) {
- hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
+ int i;
+
+ for (i = 0; i < 8; i += 2) {
+ u8 lane, pol;
+ int dx, dy;
+
+ dx = lanes[i];
+ dy = lanes[i + 1];
+
+ if (dx < 0 || dx >= 8)
+ return -EINVAL;
+
+ if (dy < 0 || dy >= 8)
+ return -EINVAL;
+
+ if (dx & 1) {
+ if (dy != dx - 1)
+ return -EINVAL;
+ pol = 1;
+ } else {
+ if (dy != dx + 1)
+ return -EINVAL;
+ pol = 0;
+ }
+
+ lane = dx / 2;
+
+ phy->lane_function[lane] = i / 2;
+ phy->lane_polarity[lane] = pol;
}
- return IRQ_HANDLED;
+ return 0;
}
-int hdmi_phy_enable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp,
- struct hdmi_config *cfg)
+static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy)
{
- u16 r = 0;
- u32 irqstatus;
-
- hdmi_wp_clear_irqenable(wp, 0xffffffff);
-
- irqstatus = hdmi_wp_get_irqstatus(wp);
- hdmi_wp_set_irqstatus(wp, irqstatus);
+ static const u16 pad_cfg_list[] = {
+ 0x0123,
+ 0x0132,
+ 0x0312,
+ 0x0321,
+ 0x0231,
+ 0x0213,
+ 0x1023,
+ 0x1032,
+ 0x3012,
+ 0x3021,
+ 0x2031,
+ 0x2013,
+ 0x1203,
+ 0x1302,
+ 0x3102,
+ 0x3201,
+ 0x2301,
+ 0x2103,
+ 0x1230,
+ 0x1320,
+ 0x3120,
+ 0x3210,
+ 0x2310,
+ 0x2130,
+ };
+
+ u16 lane_cfg = 0;
+ int i;
+ unsigned lane_cfg_val;
+ u16 pol_val = 0;
+
+ for (i = 0; i < 4; ++i)
+ lane_cfg |= phy->lane_function[i] << ((3 - i) * 4);
+
+ pol_val |= phy->lane_polarity[0] << 0;
+ pol_val |= phy->lane_polarity[1] << 3;
+ pol_val |= phy->lane_polarity[2] << 2;
+ pol_val |= phy->lane_polarity[3] << 1;
+
+ for (i = 0; i < ARRAY_SIZE(pad_cfg_list); ++i)
+ if (pad_cfg_list[i] == lane_cfg)
+ break;
+
+ if (WARN_ON(i == ARRAY_SIZE(pad_cfg_list)))
+ i = 0;
+
+ lane_cfg_val = i;
+
+ REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, lane_cfg_val, 26, 22);
+ REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27);
+}
- r = hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_LDOON);
- if (r)
- return r;
+int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg)
+{
+ u8 freqout;
/*
* Read address 0 in order to get the SCP reset done completed
@@ -81,79 +143,112 @@ int hdmi_phy_enable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp,
hdmi_read_reg(phy->base, HDMI_TXPHY_TX_CTRL);
/*
+ * In OMAP5+, the HFBITCLK must be divided by 2 before issuing the
+ * HDMI_PHYPWRCMD_LDOON command.
+ */
+ if (phy_feat->bist_ctrl)
+ REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11);
+
+ if (phy_feat->calc_freqout) {
+ /* DCOCLK/10 is pixel clock, compare pclk with DCOCLK_MIN/10 */
+ u32 dco_min = phy_feat->dcofreq_min / 10;
+ u32 pclk = cfg->timings.pixelclock;
+
+ if (pclk < dco_min)
+ freqout = 0;
+ else if ((pclk >= dco_min) && (pclk < phy_feat->max_phy))
+ freqout = 1;
+ else
+ freqout = 2;
+ } else {
+ freqout = 1;
+ }
+
+ /*
* Write to phy address 0 to configure the clock
* use HFBITCLK write HDMI_TXPHY_TX_CONTROL_FREQOUT field
*/
- REG_FLD_MOD(phy->base, HDMI_TXPHY_TX_CTRL, 0x1, 31, 30);
+ REG_FLD_MOD(phy->base, HDMI_TXPHY_TX_CTRL, freqout, 31, 30);
/* Write to phy address 1 to start HDMI line (TXVALID and TMDSCLKEN) */
hdmi_write_reg(phy->base, HDMI_TXPHY_DIGITAL_CTRL, 0xF0000000);
/* Setup max LDO voltage */
- REG_FLD_MOD(phy->base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0);
+ if (phy_feat->ldo_voltage)
+ REG_FLD_MOD(phy->base, HDMI_TXPHY_POWER_CTRL, 0xB, 3, 0);
- /* Write to phy address 3 to change the polarity control */
- REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, 0x1, 27, 27);
-
- r = request_threaded_irq(phy->irq, NULL, hdmi_irq_handler,
- IRQF_ONESHOT, "OMAP HDMI", wp);
- if (r) {
- DSSERR("HDMI IRQ request failed\n");
- hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
- return r;
- }
-
- hdmi_wp_set_irqenable(wp,
- HDMI_IRQ_LINK_CONNECT | HDMI_IRQ_LINK_DISCONNECT);
+ hdmi_phy_configure_lanes(phy);
return 0;
}
-void hdmi_phy_disable(struct hdmi_phy_data *phy, struct hdmi_wp_data *wp)
+static const struct hdmi_phy_features omap44xx_phy_feats = {
+ .bist_ctrl = false,
+ .calc_freqout = false,
+ .ldo_voltage = true,
+ .dcofreq_min = 500000000,
+ .max_phy = 185675000,
+};
+
+static const struct hdmi_phy_features omap54xx_phy_feats = {
+ .bist_ctrl = true,
+ .calc_freqout = true,
+ .ldo_voltage = false,
+ .dcofreq_min = 750000000,
+ .max_phy = 186000000,
+};
+
+static int hdmi_phy_init_features(struct platform_device *pdev)
{
- free_irq(phy->irq, wp);
+ struct hdmi_phy_features *dst;
+ const struct hdmi_phy_features *src;
- hdmi_wp_set_phy_pwr(wp, HDMI_PHYPWRCMD_OFF);
-}
+ dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
+ if (!dst) {
+ dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n");
+ return -ENOMEM;
+ }
+
+ switch (omapdss_get_version()) {
+ case OMAPDSS_VER_OMAP4430_ES1:
+ case OMAPDSS_VER_OMAP4430_ES2:
+ case OMAPDSS_VER_OMAP4:
+ src = &omap44xx_phy_feats;
+ break;
-#define PHY_OFFSET 0x300
-#define PHY_SIZE 0x100
+ case OMAPDSS_VER_OMAP5:
+ src = &omap54xx_phy_feats;
+ break;
+
+ default:
+ return -ENODEV;
+ }
+
+ memcpy(dst, src, sizeof(*dst));
+ phy_feat = dst;
+
+ return 0;
+}
int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy)
{
+ int r;
struct resource *res;
- struct resource temp_res;
+
+ r = hdmi_phy_init_features(pdev);
+ if (r)
+ return r;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy");
if (!res) {
- DSSDBG("can't get PHY mem resource by name\n");
- /*
- * if hwmod/DT doesn't have the memory resource information
- * split into HDMI sub blocks by name, we try again by getting
- * the platform's first resource. this code will be removed when
- * the driver can get the mem resources by name
- */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- DSSERR("can't get PHY mem resource\n");
- return -EINVAL;
- }
-
- temp_res.start = res->start + PHY_OFFSET;
- temp_res.end = temp_res.start + PHY_SIZE - 1;
- res = &temp_res;
+ DSSERR("can't get PHY mem resource\n");
+ return -EINVAL;
}
- phy->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!phy->base) {
+ phy->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(phy->base)) {
DSSERR("can't ioremap TX PHY\n");
- return -ENOMEM;
- }
-
- phy->irq = platform_get_irq(pdev, 0);
- if (phy->irq < 0) {
- DSSERR("platform_get_irq failed\n");
- return -ENODEV;
+ return PTR_ERR(phy->base);
}
return 0;
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_pll.c b/drivers/video/fbdev/omap2/dss/hdmi_pll.c
index 5fc71215c303..54df12a8d744 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_pll.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_pll.c
@@ -23,6 +23,18 @@
#define HDMI_DEFAULT_REGN 16
#define HDMI_DEFAULT_REGM2 1
+struct hdmi_pll_features {
+ bool sys_reset;
+ /* this is a hack, need to replace it with a better computation of M2 */
+ bool bound_dcofreq;
+ unsigned long fint_min, fint_max;
+ u16 regm_max;
+ unsigned long dcofreq_low_min, dcofreq_low_max;
+ unsigned long dcofreq_high_min, dcofreq_high_max;
+};
+
+static const struct hdmi_pll_features *pll_feat;
+
void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
{
#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
@@ -57,7 +69,11 @@ void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy)
refclk = clkin / pi->regn;
- pi->regm2 = HDMI_DEFAULT_REGM2;
+ /* temorary hack to make sure DCO freq isn't calculated too low */
+ if (pll_feat->bound_dcofreq && phy <= 65000)
+ pi->regm2 = 3;
+ else
+ pi->regm2 = HDMI_DEFAULT_REGM2;
/*
* multiplier is pixel_clk/ref_clk
@@ -154,7 +170,7 @@ static int hdmi_pll_config(struct hdmi_pll_data *pll)
static int hdmi_pll_reset(struct hdmi_pll_data *pll)
{
/* SYSRESET controlled by power FSM */
- REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 3, 3);
+ REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, pll_feat->sys_reset, 3, 3);
/* READ 0x0 reset is in progress */
if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_STATUS, 0, 0, 1)
@@ -194,38 +210,81 @@ void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
}
-#define PLL_OFFSET 0x200
-#define PLL_SIZE 0x100
+static const struct hdmi_pll_features omap44xx_pll_feats = {
+ .sys_reset = false,
+ .bound_dcofreq = false,
+ .fint_min = 500000,
+ .fint_max = 2500000,
+ .regm_max = 4095,
+ .dcofreq_low_min = 500000000,
+ .dcofreq_low_max = 1000000000,
+ .dcofreq_high_min = 1000000000,
+ .dcofreq_high_max = 2000000000,
+};
+
+static const struct hdmi_pll_features omap54xx_pll_feats = {
+ .sys_reset = true,
+ .bound_dcofreq = true,
+ .fint_min = 620000,
+ .fint_max = 2500000,
+ .regm_max = 2046,
+ .dcofreq_low_min = 750000000,
+ .dcofreq_low_max = 1500000000,
+ .dcofreq_high_min = 1250000000,
+ .dcofreq_high_max = 2500000000UL,
+};
+
+static int hdmi_pll_init_features(struct platform_device *pdev)
+{
+ struct hdmi_pll_features *dst;
+ const struct hdmi_pll_features *src;
+
+ dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
+ if (!dst) {
+ dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n");
+ return -ENOMEM;
+ }
+
+ switch (omapdss_get_version()) {
+ case OMAPDSS_VER_OMAP4430_ES1:
+ case OMAPDSS_VER_OMAP4430_ES2:
+ case OMAPDSS_VER_OMAP4:
+ src = &omap44xx_pll_feats;
+ break;
+
+ case OMAPDSS_VER_OMAP5:
+ src = &omap54xx_pll_feats;
+ break;
+
+ default:
+ return -ENODEV;
+ }
+
+ memcpy(dst, src, sizeof(*dst));
+ pll_feat = dst;
+
+ return 0;
+}
int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll)
{
+ int r;
struct resource *res;
- struct resource temp_res;
+
+ r = hdmi_pll_init_features(pdev);
+ if (r)
+ return r;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll");
if (!res) {
- DSSDBG("can't get PLL mem resource by name\n");
- /*
- * if hwmod/DT doesn't have the memory resource information
- * split into HDMI sub blocks by name, we try again by getting
- * the platform's first resource. this code will be removed when
- * the driver can get the mem resources by name
- */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- DSSERR("can't get PLL mem resource\n");
- return -EINVAL;
- }
-
- temp_res.start = res->start + PLL_OFFSET;
- temp_res.end = temp_res.start + PLL_SIZE - 1;
- res = &temp_res;
+ DSSERR("can't get PLL mem resource\n");
+ return -EINVAL;
}
- pll->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!pll->base) {
+ pll->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pll->base)) {
DSSERR("can't ioremap PLLCTRL\n");
- return -ENOMEM;
+ return PTR_ERR(pll->base);
}
return 0;
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_wp.c b/drivers/video/fbdev/omap2/dss/hdmi_wp.c
index f5f4ccf50d90..496327e2b21b 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_wp.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_wp.c
@@ -185,7 +185,7 @@ void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
timings->interlace = param->timings.interlace;
}
-#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
+#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) || defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
struct hdmi_audio_format *aud_fmt)
{
@@ -238,37 +238,20 @@ int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable)
}
#endif
-#define WP_SIZE 0x200
-
int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
{
struct resource *res;
- struct resource temp_res;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "wp");
if (!res) {
- DSSDBG("can't get WP mem resource by name\n");
- /*
- * if hwmod/DT doesn't have the memory resource information
- * split into HDMI sub blocks by name, we try again by getting
- * the platform's first resource. this code will be removed when
- * the driver can get the mem resources by name
- */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- DSSERR("can't get WP mem resource\n");
- return -EINVAL;
- }
-
- temp_res.start = res->start;
- temp_res.end = temp_res.start + WP_SIZE - 1;
- res = &temp_res;
+ DSSERR("can't get WP mem resource\n");
+ return -EINVAL;
}
- wp->base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
- if (!wp->base) {
+ wp->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(wp->base)) {
DSSERR("can't ioremap HDMI WP\n");
- return -ENOMEM;
+ return PTR_ERR(wp->base);
}
return 0;
diff --git a/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c b/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c
new file mode 100644
index 000000000000..99af9e88b2d8
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2014 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@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.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * As omapdss panel drivers are omapdss specific, but we want to define the
+ * DT-data in generic manner, we convert the compatible strings of the panel and
+ * encoder nodes from "panel-foo" to "omapdss,panel-foo". This way we can have
+ * both correct DT data and omapdss specific drivers.
+ *
+ * When we get generic panel drivers to the kernel, this file will be removed.
+ */
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+
+static struct list_head dss_conv_list __initdata;
+
+static const char prefix[] __initconst = "omapdss,";
+
+struct dss_conv_node {
+ struct list_head list;
+ struct device_node *node;
+ bool root;
+};
+
+static int __init omapdss_count_strings(const struct property *prop)
+{
+ const char *p = prop->value;
+ int l = 0, total = 0;
+ int i;
+
+ for (i = 0; total < prop->length; total += l, p += l, i++)
+ l = strlen(p) + 1;
+
+ return i;
+}
+
+static void __init omapdss_update_prop(struct device_node *node, char *compat,
+ int len)
+{
+ struct property *prop;
+
+ prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+ if (!prop)
+ return;
+
+ prop->name = "compatible";
+ prop->value = compat;
+ prop->length = len;
+
+ of_update_property(node, prop);
+}
+
+static void __init omapdss_prefix_strcpy(char *dst, int dst_len,
+ const char *src, int src_len)
+{
+ size_t total = 0;
+
+ while (total < src_len) {
+ size_t l = strlen(src) + 1;
+
+ strcpy(dst, prefix);
+ dst += strlen(prefix);
+
+ strcpy(dst, src);
+ dst += l;
+
+ src += l;
+ total += l;
+ }
+}
+
+/* prepend compatible property strings with "omapdss," */
+static void __init omapdss_omapify_node(struct device_node *node)
+{
+ struct property *prop;
+ char *new_compat;
+ int num_strs;
+ int new_len;
+
+ prop = of_find_property(node, "compatible", NULL);
+
+ if (!prop || !prop->value)
+ return;
+
+ if (strnlen(prop->value, prop->length) >= prop->length)
+ return;
+
+ /* is it already prefixed? */
+ if (strncmp(prefix, prop->value, strlen(prefix)) == 0)
+ return;
+
+ num_strs = omapdss_count_strings(prop);
+
+ new_len = prop->length + strlen(prefix) * num_strs;
+ new_compat = kmalloc(new_len, GFP_KERNEL);
+
+ omapdss_prefix_strcpy(new_compat, new_len, prop->value, prop->length);
+
+ omapdss_update_prop(node, new_compat, new_len);
+}
+
+static void __init omapdss_add_to_list(struct device_node *node, bool root)
+{
+ struct dss_conv_node *n = kmalloc(sizeof(struct dss_conv_node),
+ GFP_KERNEL);
+ n->node = node;
+ n->root = root;
+ list_add(&n->list, &dss_conv_list);
+}
+
+static bool __init omapdss_list_contains(const struct device_node *node)
+{
+ struct dss_conv_node *n;
+
+ list_for_each_entry(n, &dss_conv_list, list) {
+ if (n->node == node)
+ return true;
+ }
+
+ return false;
+}
+
+static void __init omapdss_walk_device(struct device_node *node, bool root)
+{
+ struct device_node *n;
+
+ omapdss_add_to_list(node, root);
+
+ /*
+ * of_graph_get_remote_port_parent() prints an error if there is no
+ * port/ports node. To avoid that, check first that there's the node.
+ */
+ n = of_get_child_by_name(node, "ports");
+ if (!n)
+ n = of_get_child_by_name(node, "port");
+ if (!n)
+ return;
+
+ of_node_put(n);
+
+ n = NULL;
+ while ((n = of_graph_get_next_endpoint(node, n)) != NULL) {
+ struct device_node *pn;
+
+ pn = of_graph_get_remote_port_parent(n);
+
+ if (!pn) {
+ of_node_put(n);
+ continue;
+ }
+
+ if (!of_device_is_available(pn) || omapdss_list_contains(pn)) {
+ of_node_put(pn);
+ of_node_put(n);
+ continue;
+ }
+
+ omapdss_walk_device(pn, false);
+
+ of_node_put(n);
+ }
+}
+
+static const struct of_device_id omapdss_of_match[] __initconst = {
+ { .compatible = "ti,omap2-dss", },
+ { .compatible = "ti,omap3-dss", },
+ { .compatible = "ti,omap4-dss", },
+ { .compatible = "ti,omap5-dss", },
+ {},
+};
+
+static int __init omapdss_boot_init(void)
+{
+ struct device_node *dss, *child;
+
+ INIT_LIST_HEAD(&dss_conv_list);
+
+ dss = of_find_matching_node(NULL, omapdss_of_match);
+
+ if (dss == NULL || !of_device_is_available(dss))
+ return 0;
+
+ omapdss_walk_device(dss, true);
+
+ for_each_available_child_of_node(dss, child) {
+ if (!of_find_property(child, "compatible", NULL)) {
+ of_node_put(child);
+ continue;
+ }
+
+ omapdss_walk_device(child, true);
+ }
+
+ while (!list_empty(&dss_conv_list)) {
+ struct dss_conv_node *n;
+
+ n = list_first_entry(&dss_conv_list, struct dss_conv_node,
+ list);
+
+ if (!n->root)
+ omapdss_omapify_node(n->node);
+
+ list_del(&n->list);
+ of_node_put(n->node);
+ kfree(n);
+ }
+
+ return 0;
+}
+
+subsys_initcall(omapdss_boot_init);
diff --git a/drivers/video/fbdev/omap2/dss/venc_panel.c b/drivers/video/fbdev/omap2/dss/venc_panel.c
deleted file mode 100644
index af68cd444d7e..000000000000
--- a/drivers/video/fbdev/omap2/dss/venc_panel.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright (C) 2009 Nokia Corporation
- * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
- *
- * VENC panel driver
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published by
- * the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <linux/kernel.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/mutex.h>
-#include <linux/module.h>
-
-#include <video/omapdss.h>
-
-#include "dss.h"
-
-static struct {
- struct mutex lock;
-} venc_panel;
-
-static ssize_t display_output_type_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct omap_dss_device *dssdev = to_dss_device(dev);
- const char *ret;
-
- switch (dssdev->phy.venc.type) {
- case OMAP_DSS_VENC_TYPE_COMPOSITE:
- ret = "composite";
- break;
- case OMAP_DSS_VENC_TYPE_SVIDEO:
- ret = "svideo";
- break;
- default:
- return -EINVAL;
- }
-
- return snprintf(buf, PAGE_SIZE, "%s\n", ret);
-}
-
-static ssize_t display_output_type_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t size)
-{
- struct omap_dss_device *dssdev = to_dss_device(dev);
- enum omap_dss_venc_type new_type;
-
- if (sysfs_streq("composite", buf))
- new_type = OMAP_DSS_VENC_TYPE_COMPOSITE;
- else if (sysfs_streq("svideo", buf))
- new_type = OMAP_DSS_VENC_TYPE_SVIDEO;
- else
- return -EINVAL;
-
- mutex_lock(&venc_panel.lock);
-
- if (dssdev->phy.venc.type != new_type) {
- dssdev->phy.venc.type = new_type;
- omapdss_venc_set_type(dssdev, new_type);
- if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
- omapdss_venc_display_disable(dssdev);
- omapdss_venc_display_enable(dssdev);
- }
- }
-
- mutex_unlock(&venc_panel.lock);
-
- return size;
-}
-
-static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR,
- display_output_type_show, display_output_type_store);
-
-static int venc_panel_probe(struct omap_dss_device *dssdev)
-{
- /* set default timings to PAL */
- const struct omap_video_timings default_timings = {
- .x_res = 720,
- .y_res = 574,
- .pixelclock = 13500000,
- .hsw = 64,
- .hfp = 12,
- .hbp = 68,
- .vsw = 5,
- .vfp = 5,
- .vbp = 41,
-
- .vsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
- .hsync_level = OMAPDSS_SIG_ACTIVE_HIGH,
-
- .interlace = true,
- };
-
- mutex_init(&venc_panel.lock);
-
- dssdev->panel.timings = default_timings;
-
- return device_create_file(dssdev->dev, &dev_attr_output_type);
-}
-
-static void venc_panel_remove(struct omap_dss_device *dssdev)
-{
- device_remove_file(dssdev->dev, &dev_attr_output_type);
-}
-
-static int venc_panel_enable(struct omap_dss_device *dssdev)
-{
- int r;
-
- dev_dbg(dssdev->dev, "venc_panel_enable\n");
-
- mutex_lock(&venc_panel.lock);
-
- if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
- r = -EINVAL;
- goto err;
- }
-
- omapdss_venc_set_timings(dssdev, &dssdev->panel.timings);
- omapdss_venc_set_type(dssdev, dssdev->phy.venc.type);
- omapdss_venc_invert_vid_out_polarity(dssdev,
- dssdev->phy.venc.invert_polarity);
-
- r = omapdss_venc_display_enable(dssdev);
- if (r)
- goto err;
-
- dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
-
- mutex_unlock(&venc_panel.lock);
-
- return 0;
-err:
- mutex_unlock(&venc_panel.lock);
-
- return r;
-}
-
-static void venc_panel_disable(struct omap_dss_device *dssdev)
-{
- dev_dbg(dssdev->dev, "venc_panel_disable\n");
-
- mutex_lock(&venc_panel.lock);
-
- if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
- goto end;
-
- omapdss_venc_display_disable(dssdev);
-
- dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
-end:
- mutex_unlock(&venc_panel.lock);
-}
-
-static void venc_panel_set_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings)
-{
- dev_dbg(dssdev->dev, "venc_panel_set_timings\n");
-
- mutex_lock(&venc_panel.lock);
-
- omapdss_venc_set_timings(dssdev, timings);
- dssdev->panel.timings = *timings;
-
- mutex_unlock(&venc_panel.lock);
-}
-
-static int venc_panel_check_timings(struct omap_dss_device *dssdev,
- struct omap_video_timings *timings)
-{
- dev_dbg(dssdev->dev, "venc_panel_check_timings\n");
-
- return omapdss_venc_check_timings(dssdev, timings);
-}
-
-static u32 venc_panel_get_wss(struct omap_dss_device *dssdev)
-{
- dev_dbg(dssdev->dev, "venc_panel_get_wss\n");
-
- return omapdss_venc_get_wss(dssdev);
-}
-
-static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss)
-{
- dev_dbg(dssdev->dev, "venc_panel_set_wss\n");
-
- return omapdss_venc_set_wss(dssdev, wss);
-}
-
-static struct omap_dss_driver venc_driver = {
- .probe = venc_panel_probe,
- .remove = venc_panel_remove,
-
- .enable = venc_panel_enable,
- .disable = venc_panel_disable,
-
- .get_resolution = omapdss_default_get_resolution,
- .get_recommended_bpp = omapdss_default_get_recommended_bpp,
-
- .set_timings = venc_panel_set_timings,
- .check_timings = venc_panel_check_timings,
-
- .get_wss = venc_panel_get_wss,
- .set_wss = venc_panel_set_wss,
-
- .driver = {
- .name = "venc",
- .owner = THIS_MODULE,
- },
-};
-
-int venc_panel_init(void)
-{
- return omap_dss_register_driver(&venc_driver);
-}
-
-void venc_panel_exit(void)
-{
- omap_dss_unregister_driver(&venc_driver);
-}
diff --git a/drivers/video/fbdev/pxa3xx-gcu.c b/drivers/video/fbdev/pxa3xx-gcu.c
index 417f9a27eb7d..4df3657fe221 100644
--- a/drivers/video/fbdev/pxa3xx-gcu.c
+++ b/drivers/video/fbdev/pxa3xx-gcu.c
@@ -612,11 +612,9 @@ static int pxa3xx_gcu_probe(struct platform_device *pdev)
/* handle IO resources */
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- priv->mmio_base = devm_request_and_ioremap(dev, r);
- if (IS_ERR(priv->mmio_base)) {
- dev_err(dev, "failed to map I/O memory\n");
+ priv->mmio_base = devm_ioremap_resource(dev, r);
+ if (IS_ERR(priv->mmio_base))
return PTR_ERR(priv->mmio_base);
- }
/* enable the clock */
priv->clk = devm_clk_get(dev, NULL);
diff --git a/drivers/video/fbdev/s3fb.c b/drivers/video/fbdev/s3fb.c
index 9a3f8f1c6aab..c43b969e1e23 100644
--- a/drivers/video/fbdev/s3fb.c
+++ b/drivers/video/fbdev/s3fb.c
@@ -1401,9 +1401,10 @@ err_enable_device:
static void s3_pci_remove(struct pci_dev *dev)
{
struct fb_info *info = pci_get_drvdata(dev);
- struct s3fb_info __maybe_unused *par = info->par;
+ struct s3fb_info __maybe_unused *par;
if (info) {
+ par = info->par;
#ifdef CONFIG_MTRR
if (par->mtrr_reg >= 0) {
diff --git a/drivers/video/fbdev/wm8505fb.c b/drivers/video/fbdev/wm8505fb.c
index 537d199612af..d2fafbbcd7f8 100644
--- a/drivers/video/fbdev/wm8505fb.c
+++ b/drivers/video/fbdev/wm8505fb.c
@@ -162,7 +162,7 @@ static ssize_t contrast_show(struct device *dev,
struct fb_info *info = dev_get_drvdata(dev);
struct wm8505fb_info *fbi = to_wm8505fb_info(info);
- return sprintf(buf, "%d\n", fbi->contrast);
+ return sprintf(buf, "%u\n", fbi->contrast);
}
static ssize_t contrast_store(struct device *dev,
diff --git a/drivers/video/of_display_timing.c b/drivers/video/of_display_timing.c
index ba5b40f581f6..987edf110038 100644
--- a/drivers/video/of_display_timing.c
+++ b/drivers/video/of_display_timing.c
@@ -115,10 +115,8 @@ int of_get_display_timing(struct device_node *np, const char *name,
{
struct device_node *timing_np;
- if (!np) {
- pr_err("%s: no devicenode given\n", of_node_full_name(np));
+ if (!np)
return -EINVAL;
- }
timing_np = of_get_child_by_name(np, name);
if (!timing_np) {
@@ -142,10 +140,8 @@ struct display_timings *of_get_display_timings(struct device_node *np)
struct device_node *native_mode;
struct display_timings *disp;
- if (!np) {
- pr_err("%s: no device node given\n", of_node_full_name(np));
+ if (!np)
return NULL;
- }
timings_np = of_get_child_by_name(np, "display-timings");
if (!timings_np) {
@@ -164,7 +160,7 @@ struct display_timings *of_get_display_timings(struct device_node *np)
entry = of_parse_phandle(timings_np, "native-mode", 0);
/* assume first child as native mode if none provided */
if (!entry)
- entry = of_get_next_child(np, NULL);
+ entry = of_get_next_child(timings_np, NULL);
/* if there is no child, it is useless to go on */
if (!entry) {
pr_err("%s: no timing specifications given\n",
OpenPOWER on IntegriCloud